Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: tests/compiler/dart2js/lookup_map_test.dart

Issue 1310183014: Generalize lookup-maps to support other const keys (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library tests.dart2js.lookup_map_test; 5 library tests.dart2js.lookup_map_test;
6 6
7 import 'package:test/test.dart'; 7 import 'package:test/test.dart';
8 import 'compiler_helper.dart'; 8 import 'compiler_helper.dart';
9 9
10 main() { 10 main() {
11 Map<String, String> testDeclarations = {
12 'types': r'''
13 import 'package:lookup_map/lookup_map.dart';
14 class A {}
15 class B {}
16 class C {}
17 class D {}
18 class E {}''',
19
20 'const keys': r'''
21 import 'package:lookup_map/lookup_map.dart';
22 class Key { final name; const Key(this.name); }
23 const A = const Key("A");
24 const B = const Key("B");
25 const C = const Key("C");
26 const D = const Key("D");
27 const E = const Key("E");''',
28
29 'mixed keys': r'''
30 import 'package:lookup_map/lookup_map.dart';
31 class Key { final name; const Key(this.name); }
32 const A = const Key("A");
33 class B {}
34 const C = const Key("C");
35 class D {}
36 const E = const Key("E");''',
37 };
38
39 testDeclarations.forEach((name, declarations) {
40 group(name, () => _commonTests(declarations));
41 });
42 group('generic', _genericTests);
43 group('metadata', _metadataTests);
44 group('unsupported', _unsupportedKeysTests);
45 }
46
47 /// Common tests for both declarations that use Types or other const expressions
48 /// as keys. The argument [declaration] should contain a declaration for
49 /// constant keys named `A`, `B`, `C`, `D`, and `E`.
50 _commonTests(String declarations) {
11 test('live entries are kept', () async { 51 test('live entries are kept', () async {
12 String generated = await compileAll(r""" 52 String generated = await compileAll("""
13 import 'package:lookup_map/lookup_map.dart'; 53 $declarations
14 class A{}
15 const map = const LookupMap(const [ 54 const map = const LookupMap(const [
16 A, "the-text-for-A", 55 A, "the-text-for-A",
17 ]); 56 ]);
18 main() => print(map[A]); 57 main() => print(map[A]);
19 """); 58 """);
20 expect(generated, contains("the-text-for-A")); 59 expect(generated, contains("the-text-for-A"));
21 }); 60 });
22 61
23 test('live entries are kept - single-pair', () async { 62 test('live entries are kept - single-pair', () async {
24 String generated = await compileAll(r""" 63 String generated = await compileAll("""
25 import 'package:lookup_map/lookup_map.dart'; 64 $declarations
26 class A{}
27 const map = const LookupMap.pair(A, "the-text-for-A"); 65 const map = const LookupMap.pair(A, "the-text-for-A");
28 main() => print(map[A]); 66 main() => print(map[A]);
29 """); 67 """);
30 expect(generated, contains("the-text-for-A")); 68 expect(generated, contains("the-text-for-A"));
31 }); 69 });
32 70
33 test('unused entries are removed', () async { 71 test('unused entries are removed', () async {
34 String generated = await compileAll(r""" 72 String generated = await compileAll("""
35 import 'package:lookup_map/lookup_map.dart'; 73 $declarations
36 class A{}
37 class B{}
38 const map = const LookupMap(const [ 74 const map = const LookupMap(const [
39 A, "the-text-for-A", 75 A, "the-text-for-A",
40 B, "the-text-for-B", 76 B, "the-text-for-B",
41 ]); 77 ]);
42 main() => print(map[A]); 78 main() => print(map[A]);
43 """); 79 """);
44 expect(generated, isNot(contains("the-text-for-B"))); 80 expect(generated, isNot(contains("the-text-for-B")));
45 }); 81 });
46 82
47 test('unused entries are removed - nested maps', () async { 83 test('unused entries are removed - nested maps', () async {
48 String generated = await compileAll(r""" 84 String generated = await compileAll("""
49 import 'package:lookup_map/lookup_map.dart'; 85 $declarations
50 class A{}
51 class B{}
52 const map = const LookupMap(const [], const [ 86 const map = const LookupMap(const [], const [
53 const LookupMap(const [ 87 const LookupMap(const [
54 A, "the-text-for-A", 88 A, "the-text-for-A",
55 B, "the-text-for-B", 89 B, "the-text-for-B",
56 ]), 90 ]),
57 ]); 91 ]);
58 main() => print(map[A]); 92 main() => print(map[A]);
59 """); 93 """);
60 expect(generated, isNot(contains("the-text-for-B"))); 94 expect(generated, isNot(contains("the-text-for-B")));
61 }); 95 });
62 96
63 test('unused entries are removed - single-pair', () async { 97 test('unused entries are removed - single-pair', () async {
64 String generated = await compileAll(r""" 98 String generated = await compileAll("""
65 import 'package:lookup_map/lookup_map.dart'; 99 $declarations
66 class A{}
67 class B{}
68 const map = const LookupMap.pair(A, "the-text-for-A"); 100 const map = const LookupMap.pair(A, "the-text-for-A");
69 main() => print(map[A]); 101 main() => print(map[A]);
70 """); 102 """);
71 expect(generated, isNot(contains("the-text-for-B"))); 103 expect(generated, isNot(contains("the-text-for-B")));
72 }); 104 });
73 105
74 test('unused entries are removed - nested single-pair', () async { 106 test('unused entries are removed - nested single-pair', () async {
75 String generated = await compileAll(r""" 107 String generated = await compileAll("""
76 import 'package:lookup_map/lookup_map.dart'; 108 import 'package:lookup_map/lookup_map.dart';
77 class A{} 109 $declarations
78 class B{}
79 const map = const LookupMap(const [], const [ 110 const map = const LookupMap(const [], const [
80 const LookupMap.pair(A, "the-text-for-A"), 111 const LookupMap.pair(A, "the-text-for-A"),
81 const LookupMap.pair(B, "the-text-for-B"), 112 const LookupMap.pair(B, "the-text-for-B"),
82 ]); 113 ]);
83 main() => print(map[A]); 114 main() => print(map[A]);
84 """); 115 """);
85 expect(generated, isNot(contains("the-text-for-B"))); 116 expect(generated, isNot(contains("the-text-for-B")));
86 }); 117 });
87 118
88 test('works if entries are declared separate from map', () async { 119 test('works if entries are declared separate from map', () async {
89 String generated = await compileAll(r""" 120 String generated = await compileAll("""
90 import 'package:lookup_map/lookup_map.dart'; 121 $declarations
91 class A{}
92 class B{}
93 const entries = const [ 122 const entries = const [
94 A, "the-text-for-A", 123 A, "the-text-for-A",
95 B, "the-text-for-B", 124 B, "the-text-for-B",
96 ]; 125 ];
97 const map = const LookupMap(entries); 126 const map = const LookupMap(entries);
98 main() => print(map[A]); 127 main() => print(map[A]);
99 """); 128 """);
100 expect(generated, isNot(contains("the-text-for-B"))); 129 expect(generated, isNot(contains("the-text-for-B")));
101 }); 130 });
102 131
103 test('escaping entries disable tree-shaking', () async { 132 test('escaping entries disable tree-shaking', () async {
104 String generated = await compileAll(r""" 133 String generated = await compileAll("""
105 import 'package:lookup_map/lookup_map.dart'; 134 $declarations
106 class A{}
107 class B{}
108 const entries = const [ 135 const entries = const [
109 A, "the-text-for-A", 136 A, "the-text-for-A",
110 B, "the-text-for-B", 137 B, "the-text-for-B",
111 ]; 138 ];
112 const map = const LookupMap(entries); 139 const map = const LookupMap(entries);
113 main() { 140 main() {
114 entries.forEach(print); 141 entries.forEach(print);
115 print(map[A]); 142 print(map[A]);
116 } 143 }
117 """); 144 """);
118 expect(generated, contains("the-text-for-B")); 145 expect(generated, contains("the-text-for-B"));
119 }); 146 });
120 147
121 test('uses include recursively reachable data', () async { 148 test('uses include recursively reachable data', () async {
122 String generated = await compileAll(r""" 149 String generated = await compileAll("""
123 import 'package:lookup_map/lookup_map.dart'; 150 $declarations
124 class A{}
125 class B{}
126 class C{}
127 class D{}
128 class E{}
129 const map = const LookupMap(const [ 151 const map = const LookupMap(const [
130 A, const ["the-text-for-A", B], 152 A, const ["the-text-for-A", B],
131 B, const ["the-text-for-B", C], 153 B, const ["the-text-for-B", C],
132 C, const ["the-text-for-C"], 154 C, const ["the-text-for-C"],
133 D, const ["the-text-for-D", E], 155 D, const ["the-text-for-D", E],
134 E, const ["the-text-for-E"], 156 E, const ["the-text-for-E"],
135 ]); 157 ]);
136 main() => print(map[map[A][1]]); 158 main() => print(map[map[A][1]]);
137 """); 159 """);
138 expect(generated, contains("the-text-for-A")); 160 expect(generated, contains("the-text-for-A"));
139 expect(generated, contains("the-text-for-B")); 161 expect(generated, contains("the-text-for-B"));
140 expect(generated, contains("the-text-for-C")); 162 expect(generated, contains("the-text-for-C"));
141 expect(generated, isNot(contains("the-text-for-D"))); 163 expect(generated, isNot(contains("the-text-for-D")));
142 expect(generated, isNot(contains("the-text-for-E"))); 164 expect(generated, isNot(contains("the-text-for-E")));
143 }); 165 });
144 166
145 test('uses are found through newly discovered code', () async { 167 test('uses are found through newly discovered code', () async {
146 String generated = await compileAll(r""" 168 String generated = await compileAll("""
147 import 'package:lookup_map/lookup_map.dart'; 169 $declarations
148 class A{ A(B x);} 170 f1() => map[B][1]();
149 class B{} 171 f2() => E;
150 class C{}
151 class D{}
152 class E{}
153 createA() => new A(map[B][1]());
154 createB() => new B();
155 const map = const LookupMap(const [ 172 const map = const LookupMap(const [
156 A, const ["the-text-for-A", createA], 173 A, const ["the-text-for-A", f1],
157 B, const ["the-text-for-B", createB], 174 B, const ["the-text-for-B", f2],
158 C, const ["the-text-for-C"], 175 C, const ["the-text-for-C"],
176 D, const ["the-text-for-D"],
177 E, const ["the-text-for-E"],
159 ]); 178 ]);
160 main() => print(map[A][1]()); 179 main() => print(map[A][1]());
161 """); 180 """);
162 expect(generated, contains("the-text-for-A")); 181 expect(generated, contains("the-text-for-A"));
163 expect(generated, contains("the-text-for-B")); 182 expect(generated, contains("the-text-for-B"));
164 expect(generated, isNot(contains("the-text-for-C"))); 183 expect(generated, isNot(contains("the-text-for-C")));
184 expect(generated, isNot(contains("the-text-for-C")));
185 expect(generated, contains("the-text-for-E"));
165 }); 186 });
166 187
188 test('support subclassing LookupMap', () async {
189 String generated = await compileAll("""
190 $declarations
191 class S extends LookupMap {
192 const S(list) : super(list);
193 }
194 const map = const S(const [
195 A, "the-text-for-A",
196 B, "the-text-for-B",
197 ]);
198
199 main() => print(map[A]);
200 """);
201 expect(generated, contains("the-text-for-A"));
202 expect(generated, isNot(contains("the-text-for-B")));
203 });
204
205 test('constants keys are processed recursively', () async {
206 String generated = await compileAll("""
207 $declarations
208
209 const nested = const [ B ];
210 const map = const LookupMap(const [
211 A, "the-text-for-A",
212 B, "the-text-for-B",
213 ]);
214 main() => print(map[nested]);
215 """);
216 expect(generated, isNot(contains("the-text-for-A")));
217 expect(generated, contains("the-text-for-B"));
218 });
219 }
220
221 /// Tests specific to type keys, we ensure that generic type arguments are
222 /// considered.
223 _genericTests() {
167 test('generic type allocations are considered used', () async { 224 test('generic type allocations are considered used', () async {
168 String generated = await compileAll(r""" 225 String generated = await compileAll(r"""
169 import 'package:lookup_map/lookup_map.dart'; 226 import 'package:lookup_map/lookup_map.dart';
170 class A{} 227 class A{}
171 class M<T>{ get type => T; } 228 class M<T>{ get type => T; }
172 const map = const LookupMap(const [ 229 const map = const LookupMap(const [
173 A, "the-text-for-A", 230 A, "the-text-for-A",
174 ]); 231 ]);
175 main() => print(map[new M<A>().type]); 232 main() => print(map[new M<A>().type]);
176 """); 233 """);
177 expect(generated, contains("the-text-for-A")); 234 expect(generated, contains("the-text-for-A"));
178 }); 235 });
179 236
180 test('generics in type signatures are ignored', () async { 237 test('generics in type signatures are ignored', () async {
181 String generated = await compileAll(r""" 238 String generated = await compileAll(r"""
182 import 'package:lookup_map/lookup_map.dart'; 239 import 'package:lookup_map/lookup_map.dart';
183 class A{} 240 class A{}
184 class B{} 241 class B{}
185 class M<T>{ get type => T; } 242 class M<T>{ get type => T; }
186 _factory(M<B> t) => t; 243 _factory(M<B> t) => t;
187 const map = const LookupMap(const [ 244 const map = const LookupMap(const [
188 A, const ["the-text-for-A", _factory], 245 A, const ["the-text-for-A", _factory],
189 B, "the-text-for-B", 246 B, "the-text-for-B",
190 ]); 247 ]);
191 main() => print(map[A]); 248 main() => print(map[A]);
192 """); 249 """);
193 expect(generated, isNot(contains("the-text-for-B"))); 250 expect(generated, isNot(contains("the-text-for-B")));
194 }); 251 });
195 252
253 // regression test for a failure when looking up `dynamic` in a generic.
254 test('do not choke with dynamic type arguments', () async {
255 await compileAll(r"""
256 import 'package:lookup_map/lookup_map.dart';
257 class A{}
258 class M<T>{ get type => T; }
259 const map = const LookupMap(const [
260 A, "the-text-for-A",
261 ]);
262 main() => print(map[new M<dynamic>().type]);
263 """);
264 });
265 }
266
267 /// Sanity checks about metadata: it is ignored for codegen even though it is
268 /// visited during resolution.
269 _metadataTests() {
196 test('metadata is ignored', () async { 270 test('metadata is ignored', () async {
197 String generated = await compileAll(r""" 271 String generated = await compileAll(r"""
198 import 'package:lookup_map/lookup_map.dart'; 272 import 'package:lookup_map/lookup_map.dart';
199 class A{ const A(); } 273 class A{ const A(); }
200 274
201 @A() 275 @A()
202 class M {} 276 class M {}
203 const map = const LookupMap(const [ 277 const map = const LookupMap(const [
204 A, "the-text-for-A", 278 A, "the-text-for-A",
205 ]); 279 ]);
(...skipping 12 matching lines...) Expand all
218 class B{ final Type foo; const B({this.foo}); } 292 class B{ final Type foo; const B({this.foo}); }
219 293
220 class M {} 294 class M {}
221 const map = const LookupMap(const [ 295 const map = const LookupMap(const [
222 A, const ["the-text-for-A", annot] 296 A, const ["the-text-for-A", annot]
223 ]); 297 ]);
224 main() => print(map[M]); 298 main() => print(map[M]);
225 """); 299 """);
226 expect(generated, isNot(contains("the-text-for-A"))); 300 expect(generated, isNot(contains("the-text-for-A")));
227 }); 301 });
302 }
228 303
229 // regression test for a failure when looking up `dynamic` in a generic. 304 _unsupportedKeysTests() {
230 test('do not choke on dynamic types', () async { 305 test('primitive and string keys are always kept', () async {
231 await compileAll(r""" 306 String generated = await compileAll("""
232 import 'package:lookup_map/lookup_map.dart'; 307 import 'package:lookup_map/lookup_map.dart';
233 class A{} 308 const A = "A";
234 class M<T>{ get type => T; } 309 const B = "B";
235 const map = const LookupMap(const [ 310 const map = const LookupMap(const [
236 A, "the-text-for-A", 311 A, "the-text-for-A",
312 B, "the-text-for-B",
313 3, "the-text-for-3",
314 1.1, "the-text-for-1.1",
315 false, "the-text-for-false",
237 ]); 316 ]);
238 main() => print(map[new M<dynamic>().type]); 317 main() => print(map[A]);
239 """); 318 """);
319 expect(generated, contains("the-text-for-A"));
320 expect(generated, contains("the-text-for-B"));
321 expect(generated, contains("the-text-for-3"));
322 expect(generated, contains("the-text-for-1.1"));
323 expect(generated, contains("the-text-for-false"));
240 }); 324 });
241 325
242 326 test('non-type const keys implementing equals are not removed', () async {
243 test('support subclassing LookupMap', () async { 327 String generated = await compileAll("""
244 String generated = await compileAll(r"""
245 import 'package:lookup_map/lookup_map.dart'; 328 import 'package:lookup_map/lookup_map.dart';
246 class A{} 329 class Key {
247 class B{} 330 final name;
248 class S extends LookupMap { 331 const Key(this.name);
249 const S(list) : super(list); 332 int get hashCode => name.hashCode * 13;
333 operator ==(other) => other is Key && name == other.name;
250 } 334 }
251 const map = const S(const [ 335 const A = const Key("A");
336 const B = const Key("B");
337 const map = const LookupMap(const [
252 A, "the-text-for-A", 338 A, "the-text-for-A",
253 B, "the-text-for-B", 339 B, "the-text-for-B",
254 ]); 340 ]);
255
256 main() => print(map[A]); 341 main() => print(map[A]);
257 """); 342 """);
258 expect(generated, contains("the-text-for-A")); 343 expect(generated, contains("the-text-for-B"));
259 expect(generated, isNot(contains("the-text-for-B")));
260 }); 344 });
261 } 345 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698