OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 test.services.completion.statement; | 5 library test.services.completion.statement; |
6 | 6 |
7 import 'package:analysis_server/src/protocol_server.dart'; | 7 import 'package:analysis_server/src/protocol_server.dart'; |
8 import 'package:analysis_server/src/services/completion/statement/statement_comp
letion.dart'; | 8 import 'package:analysis_server/src/services/completion/statement/statement_comp
letion.dart'; |
9 import 'package:analyzer/src/dart/analysis/driver.dart'; | 9 import 'package:analyzer/src/dart/analysis/driver.dart'; |
10 import 'package:test/test.dart'; | 10 import 'package:test/test.dart'; |
11 import 'package:test_reflective_loader/test_reflective_loader.dart'; | 11 import 'package:test_reflective_loader/test_reflective_loader.dart'; |
12 | 12 |
13 import '../../../abstract_single_unit.dart'; | 13 import '../../../abstract_single_unit.dart'; |
14 | 14 |
15 main() { | 15 main() { |
16 defineReflectiveSuite(() { | 16 defineReflectiveSuite(() { |
17 defineReflectiveTests(StatementCompletionTest); | 17 defineReflectiveTests(_DoCompletionTest); |
| 18 defineReflectiveTests(_ForCompletionTest); |
| 19 defineReflectiveTests(_IfCompletionTest); |
| 20 defineReflectiveTests(_SimpleCompletionTest); |
| 21 defineReflectiveTests(_WhileCompletionTest); |
18 }); | 22 }); |
19 } | 23 } |
20 | 24 |
21 @reflectiveTest | |
22 class StatementCompletionTest extends AbstractSingleUnitTest { | 25 class StatementCompletionTest extends AbstractSingleUnitTest { |
23 SourceChange change; | 26 SourceChange change; |
24 | 27 |
25 bool get enableNewAnalysisDriver => true; | 28 bool get enableNewAnalysisDriver => true; |
26 | 29 |
27 test_completeDoEmptyCondition() async { | 30 int _after(String source, String match) => |
| 31 source.indexOf(match) + match.length; |
| 32 |
| 33 int _afterLast(String source, String match) => |
| 34 source.lastIndexOf(match) + match.length; |
| 35 |
| 36 void _assertHasChange(String message, String expectedCode, [Function cmp]) { |
| 37 if (change.message == message) { |
| 38 if (!change.edits.isEmpty) { |
| 39 String resultCode = |
| 40 SourceEdit.applySequence(testCode, change.edits[0].edits); |
| 41 expect(resultCode, expectedCode.replaceAll('////', '')); |
| 42 if (cmp != null) { |
| 43 int offset = cmp(resultCode); |
| 44 expect(change.selection.offset, offset); |
| 45 } |
| 46 } else { |
| 47 if (cmp != null) { |
| 48 int offset = cmp(testCode); |
| 49 expect(change.selection.offset, offset); |
| 50 } |
| 51 } |
| 52 return; |
| 53 } |
| 54 fail("Expected to find |$message| but got: " + change.message); |
| 55 } |
| 56 |
| 57 _computeCompletion(int offset) async { |
| 58 driver.changeFile(testFile); |
| 59 AnalysisResult result = await driver.getResult(testFile); |
| 60 StatementCompletionContext context = new StatementCompletionContext( |
| 61 testFile, |
| 62 result.lineInfo, |
| 63 offset, |
| 64 testUnit, |
| 65 testUnitElement, |
| 66 result.errors); |
| 67 StatementCompletionProcessor processor = |
| 68 new StatementCompletionProcessor(context); |
| 69 StatementCompletion completion = await processor.compute(); |
| 70 change = completion.change; |
| 71 } |
| 72 |
| 73 _prepareCompletion(String search, String sourceCode, |
| 74 {bool atStart: false, bool atEnd: false, int delta: 0}) async { |
| 75 testCode = sourceCode.replaceAll('////', ''); |
| 76 int offset = findOffset(search); |
| 77 if (atStart) { |
| 78 delta = 0; |
| 79 } else if (atEnd) { |
| 80 delta = search.length; |
| 81 } |
| 82 await _prepareCompletionAt(offset + delta, testCode); |
| 83 } |
| 84 |
| 85 _prepareCompletionAt(int offset, String sourceCode) async { |
| 86 verifyNoTestUnitErrors = false; |
| 87 await resolveTestUnit(sourceCode); |
| 88 await _computeCompletion(offset); |
| 89 } |
| 90 } |
| 91 |
| 92 @reflectiveTest |
| 93 class _DoCompletionTest extends StatementCompletionTest { |
| 94 test_emptyCondition() async { |
28 await _prepareCompletion( | 95 await _prepareCompletion( |
29 'while ()', | 96 'while ()', |
30 ''' | 97 ''' |
31 main() { | 98 main() { |
32 do { | 99 do { |
33 } while () | 100 } while () |
34 } | 101 } |
35 ''', | 102 ''', |
36 atEnd: true); | 103 atEnd: true); |
37 _assertHasChange( | 104 _assertHasChange( |
38 'Complete do-statement', | 105 'Complete do-statement', |
39 ''' | 106 ''' |
40 main() { | 107 main() { |
41 do { | 108 do { |
42 } while (); | 109 } while (); |
43 } | 110 } |
44 ''', | 111 ''', |
45 (s) => s.indexOf('while (') + 'while ('.length); | 112 (s) => _after(s, 'while (')); |
46 } | 113 } |
47 | 114 |
48 test_completeDoKeywordOnly() async { | 115 test_keywordOnly() async { |
49 await _prepareCompletion( | 116 await _prepareCompletion( |
50 'do', | 117 'do', |
51 ''' | 118 ''' |
52 main() { | 119 main() { |
53 do //// | 120 do //// |
54 } | 121 } |
55 ''', | 122 ''', |
56 atEnd: true); | 123 atEnd: true); |
57 _assertHasChange( | 124 _assertHasChange( |
58 'Complete do-statement', | 125 'Complete do-statement', |
59 ''' | 126 ''' |
60 main() { | 127 main() { |
61 do { | 128 do { |
62 //// | 129 //// |
63 } while (); | 130 } while (); |
64 } | 131 } |
65 ''', | 132 ''', |
66 (s) => s.indexOf('while (') + 'while ('.length); | 133 (s) => _after(s, 'while (')); |
67 } | 134 } |
68 | 135 |
69 test_completeDoNoBody() async { | 136 test_noBody() async { |
70 await _prepareCompletion( | 137 await _prepareCompletion( |
71 'do', | 138 'do', |
72 ''' | 139 ''' |
73 main() { | 140 main() { |
74 do; | 141 do; |
75 while | 142 while |
76 } | 143 } |
77 ''', | 144 ''', |
78 atEnd: true); | 145 atEnd: true); |
79 _assertHasChange( | 146 _assertHasChange( |
80 'Complete do-statement', | 147 'Complete do-statement', |
81 ''' | 148 ''' |
82 main() { | 149 main() { |
83 do { | 150 do { |
84 //// | 151 //// |
85 } while (); | 152 } while (); |
86 } | 153 } |
87 ''', | 154 ''', |
88 (s) => s.indexOf('while (') + 'while ('.length); | 155 (s) => _after(s, 'while (')); |
89 } | 156 } |
90 | 157 |
91 test_completeDoNoCondition() async { | 158 test_noCondition() async { |
92 await _prepareCompletion( | 159 await _prepareCompletion( |
93 'while', | 160 'while', |
94 ''' | 161 ''' |
95 main() { | 162 main() { |
96 do { | 163 do { |
97 } while | 164 } while |
98 } | 165 } |
99 ''', | 166 ''', |
100 atEnd: true); | 167 atEnd: true); |
101 _assertHasChange( | 168 _assertHasChange( |
102 'Complete do-statement', | 169 'Complete do-statement', |
103 ''' | 170 ''' |
104 main() { | 171 main() { |
105 do { | 172 do { |
106 } while (); | 173 } while (); |
107 } | 174 } |
108 ''', | 175 ''', |
109 (s) => s.indexOf('while (') + 'while ('.length); | 176 (s) => _after(s, 'while (')); |
110 } | 177 } |
111 | 178 |
112 test_completeDoNoWhile() async { | 179 test_noWhile() async { |
113 await _prepareCompletion( | 180 await _prepareCompletion( |
114 '}', | 181 '}', |
115 ''' | 182 ''' |
116 main() { | 183 main() { |
117 do { | 184 do { |
118 } | 185 } |
119 } | 186 } |
120 ''', | 187 ''', |
121 atEnd: true); | 188 atEnd: true); |
122 _assertHasChange( | 189 _assertHasChange( |
123 'Complete do-statement', | 190 'Complete do-statement', |
124 ''' | 191 ''' |
125 main() { | 192 main() { |
126 do { | 193 do { |
127 } while (); | 194 } while (); |
128 } | 195 } |
129 ''', | 196 ''', |
130 (s) => s.indexOf('while (') + 'while ('.length); | 197 (s) => _after(s, 'while (')); |
| 198 } |
| 199 } |
| 200 |
| 201 @reflectiveTest |
| 202 class _ForCompletionTest extends StatementCompletionTest { |
| 203 test_emptyCondition() async { |
| 204 await _prepareCompletion( |
| 205 '}', |
| 206 ''' |
| 207 main() { |
| 208 for (int i = 0;) { |
| 209 } |
| 210 } |
| 211 ''', |
| 212 atEnd: true); |
| 213 _assertHasChange( |
| 214 'Complete for-statement', |
| 215 ''' |
| 216 main() { |
| 217 for (int i = 0; ) { |
| 218 } |
| 219 } |
| 220 ''', |
| 221 (s) => _after(s, '0; ')); |
131 } | 222 } |
132 | 223 |
133 test_completeIfAfterCondition_BAD() async { | 224 test_emptyInitializers() async { |
| 225 await _prepareCompletion( |
| 226 '}', |
| 227 ''' |
| 228 main() { |
| 229 for () { |
| 230 } |
| 231 } |
| 232 ''', |
| 233 atEnd: true); |
| 234 _assertHasChange( |
| 235 'Complete for-statement', |
| 236 ''' |
| 237 main() { |
| 238 for () { |
| 239 } |
| 240 } |
| 241 ''', |
| 242 (s) => _after(s, 'for (')); |
| 243 } |
| 244 |
| 245 test_emptyInitializersEmptyCondition() async { |
| 246 await _prepareCompletion( |
| 247 '}', |
| 248 ''' |
| 249 main() { |
| 250 for (;/**/) { |
| 251 } |
| 252 } |
| 253 ''', |
| 254 atEnd: true); |
| 255 _assertHasChange( |
| 256 'Complete for-statement', |
| 257 ''' |
| 258 main() { |
| 259 for (;/**/) { |
| 260 } |
| 261 } |
| 262 ''', |
| 263 (s) => _after(s, '/**/')); |
| 264 } |
| 265 |
| 266 test_emptyParts() async { |
| 267 await _prepareCompletion( |
| 268 ';)', |
| 269 ''' |
| 270 main() { |
| 271 for (;;) |
| 272 } |
| 273 ''', |
| 274 atEnd: true); |
| 275 _assertHasChange( |
| 276 'Complete for-statement', |
| 277 ''' |
| 278 main() { |
| 279 for (;;) { |
| 280 //// |
| 281 } |
| 282 } |
| 283 ''', |
| 284 (s) => _after(s, ' ')); |
| 285 } |
| 286 |
| 287 test_emptyUpdaters() async { |
| 288 await _prepareCompletion( |
| 289 '}', |
| 290 ''' |
| 291 main() { |
| 292 for (int i = 0; i < 10 /**/) { |
| 293 } |
| 294 } |
| 295 ''', |
| 296 atEnd: true); |
| 297 _assertHasChange( |
| 298 'Complete for-statement', |
| 299 ''' |
| 300 main() { |
| 301 for (int i = 0; i < 10 /**/; ) { |
| 302 } |
| 303 } |
| 304 ''', |
| 305 (s) => _after(s, '10 /**/; ')); |
| 306 } |
| 307 |
| 308 test_keywordOnly() async { |
| 309 await _prepareCompletion( |
| 310 'for', |
| 311 ''' |
| 312 main() { |
| 313 for |
| 314 } |
| 315 ''', |
| 316 atEnd: true); |
| 317 _assertHasChange( |
| 318 'Complete for-statement', |
| 319 ''' |
| 320 main() { |
| 321 for () { |
| 322 //// |
| 323 } |
| 324 } |
| 325 ''', |
| 326 (s) => _after(s, 'for (')); |
| 327 } |
| 328 |
| 329 test_missingLeftSeparator() async { |
| 330 await _prepareCompletion( |
| 331 '}', |
| 332 ''' |
| 333 main() { |
| 334 for (int i = 0) { |
| 335 } |
| 336 } |
| 337 ''', |
| 338 atEnd: true); |
| 339 _assertHasChange( |
| 340 'Complete for-statement', |
| 341 ''' |
| 342 main() { |
| 343 for (int i = 0; ) { |
| 344 } |
| 345 } |
| 346 ''', |
| 347 (s) => _after(s, '0; ')); |
| 348 } |
| 349 } |
| 350 |
| 351 @reflectiveTest |
| 352 class _IfCompletionTest extends StatementCompletionTest { |
| 353 test_afterCondition_BAD() async { |
134 // TODO(messick): Fix the code to make this like test_completeIfWithConditio
n. | 354 // TODO(messick): Fix the code to make this like test_completeIfWithConditio
n. |
135 // Recap: Finding the node at the selectionOffset returns the block, not the | 355 // Recap: Finding the node at the selectionOffset returns the block, not the |
136 // if-statement. Need to understand if that only happens when the if-stateme
nt | 356 // if-statement. Need to understand if that only happens when the if-stateme
nt |
137 // is the only statement in the block, or perhaps first or last? And what | 357 // is the only statement in the block, or perhaps first or last? And what |
138 // happens when it is in the middle of other statements? | 358 // happens when it is in the middle of other statements? |
139 await _prepareCompletion( | 359 await _prepareCompletion( |
140 'if (true) ', // Trigger completion after space. | 360 'if (true) ', // Trigger completion after space. |
141 ''' | 361 ''' |
142 main() { | 362 main() { |
143 if (true) //// | 363 if (true) //// |
144 } | 364 } |
145 ''', | 365 ''', |
146 atEnd: true); | 366 atEnd: true); |
147 _assertHasChange( | 367 _assertHasChange( |
148 // Note: This is not what we want. | 368 // Note: This is not what we want. |
149 'Insert a newline at the end of the current line', | 369 'Insert a newline at the end of the current line', |
150 ''' | 370 ''' |
151 main() { | 371 main() { |
152 if (true) //// | 372 if (true) //// |
153 } | 373 } |
154 } | 374 } |
155 ''', | 375 ''', |
156 (s) => s.indexOf('if (true) ') + 'if (true) '.length); | 376 (s) => _after(s, 'if (true) ')); |
157 } | 377 } |
158 | 378 |
159 test_completeIfEmptyCondition() async { | 379 test_emptyCondition() async { |
160 await _prepareCompletion( | 380 await _prepareCompletion( |
161 'if ()', | 381 'if ()', |
162 ''' | 382 ''' |
163 main() { | 383 main() { |
164 if () | 384 if () |
165 } | 385 } |
166 ''', | 386 ''', |
167 atEnd: true); | 387 atEnd: true); |
168 _assertHasChange( | 388 _assertHasChange( |
169 'Complete if-statement', | 389 'Complete if-statement', |
170 ''' | 390 ''' |
171 main() { | 391 main() { |
172 if () { | 392 if () { |
173 //// | 393 //// |
174 } | 394 } |
175 } | 395 } |
176 ''', | 396 ''', |
177 (s) => s.indexOf('if (') + 'if ('.length); | 397 (s) => _after(s, 'if (')); |
178 } | 398 } |
179 | 399 |
180 test_completeIfKeywordOnly() async { | 400 test_keywordOnly() async { |
181 await _prepareCompletion( | 401 await _prepareCompletion( |
182 'if', | 402 'if', |
183 ''' | 403 ''' |
184 main() { | 404 main() { |
185 if //// | 405 if //// |
186 } | 406 } |
187 ''', | 407 ''', |
188 atEnd: true); | 408 atEnd: true); |
189 _assertHasChange( | 409 _assertHasChange( |
190 'Complete if-statement', | 410 'Complete if-statement', |
191 ''' | 411 ''' |
192 main() { | 412 main() { |
193 if () { | 413 if () { |
194 //// | 414 //// |
195 } | 415 } |
196 } | 416 } |
197 ''', | 417 ''', |
198 (s) => s.indexOf('if (') + 'if ('.length); | 418 (s) => _after(s, 'if (')); |
199 } | 419 } |
200 | 420 |
201 test_completeIfWithCondition() async { | 421 test_withCondition() async { |
202 await _prepareCompletion( | 422 await _prepareCompletion( |
203 'if (tr', // Trigger completion from within expression. | 423 'if (tr', // Trigger completion from within expression. |
204 ''' | 424 ''' |
205 main() { | 425 main() { |
206 if (true) | 426 if (true) |
207 } | 427 } |
208 ''', | 428 ''', |
209 atEnd: true); | 429 atEnd: true); |
210 _assertHasChange( | 430 _assertHasChange( |
211 'Complete if-statement', | 431 'Complete if-statement', |
212 ''' | 432 ''' |
213 main() { | 433 main() { |
214 if (true) { | 434 if (true) { |
215 //// | 435 //// |
216 } | 436 } |
217 } | 437 } |
218 ''', | 438 ''', |
219 (s) => s.indexOf(' ') + ' '.length); | 439 (s) => _after(s, ' ')); |
220 } | 440 } |
221 | 441 |
222 test_completeIfWithElse_BAD() async { | 442 test_withElse_BAD() async { |
223 await _prepareCompletion( | 443 await _prepareCompletion( |
224 'if ()', | 444 'if ()', |
225 ''' | 445 ''' |
226 main() { | 446 main() { |
227 if () | 447 if () |
228 else | 448 else |
229 } | 449 } |
230 ''', | 450 ''', |
231 atEnd: true); | 451 atEnd: true); |
232 _assertHasChange( | 452 _assertHasChange( |
233 // Note: if-statement completion should not trigger. | 453 // Note: if-statement completion should not trigger. |
234 'Insert a newline at the end of the current line', | 454 'Insert a newline at the end of the current line', |
235 ''' | 455 ''' |
236 main() { | 456 main() { |
237 if () | 457 if () |
238 else | 458 else |
239 } | 459 } |
240 } | 460 } |
241 ''', | 461 ''', |
242 (s) => s.indexOf('if ()') + 'if ()'.length); | 462 (s) => _after(s, 'if ()')); |
243 } | 463 } |
244 | 464 |
245 test_completeIfWithinEmptyCondition() async { | 465 test_withinEmptyCondition() async { |
246 await _prepareCompletion( | 466 await _prepareCompletion( |
247 'if (', | 467 'if (', |
248 ''' | 468 ''' |
249 main() { | 469 main() { |
250 if () | 470 if () |
251 } | 471 } |
252 ''', | 472 ''', |
253 atEnd: true); | 473 atEnd: true); |
254 _assertHasChange( | 474 _assertHasChange( |
255 'Complete if-statement', | 475 'Complete if-statement', |
256 ''' | 476 ''' |
257 main() { | 477 main() { |
258 if () { | 478 if () { |
259 //// | 479 //// |
260 } | 480 } |
261 } | 481 } |
262 ''', | 482 ''', |
263 (s) => s.indexOf('if (') + 'if ('.length); | 483 (s) => _after(s, 'if (')); |
264 } | |
265 | |
266 test_completeWhileKeywordOnly() async { | |
267 await _prepareCompletion( | |
268 'while', | |
269 ''' | |
270 main() { | |
271 while //// | |
272 } | |
273 ''', | |
274 atEnd: true); | |
275 _assertHasChange( | |
276 'Complete while-statement', | |
277 ''' | |
278 main() { | |
279 while () { | |
280 //// | |
281 } | 484 } |
282 } | 485 } |
283 ''', | |
284 (s) => s.indexOf('while (') + 'while ('.length); | |
285 } | |
286 | 486 |
287 test_simpleEnter() async { | 487 @reflectiveTest |
| 488 class _SimpleCompletionTest extends StatementCompletionTest { |
| 489 test_enter() async { |
288 await _prepareCompletion( | 490 await _prepareCompletion( |
289 'v = 1;', | 491 'v = 1;', |
290 ''' | 492 ''' |
291 main() { | 493 main() { |
292 int v = 1; | 494 int v = 1; |
293 } | 495 } |
294 ''', | 496 ''', |
295 atEnd: true); | 497 atEnd: true); |
296 _assertHasChange( | 498 _assertHasChange( |
297 'Insert a newline at the end of the current line', | 499 'Insert a newline at the end of the current line', |
298 ''' | 500 ''' |
299 main() { | 501 main() { |
300 int v = 1; | 502 int v = 1; |
301 //// | 503 //// |
302 } | 504 } |
303 '''); | 505 '''); |
304 } | 506 } |
305 | 507 |
306 test_simpleSemicolon() async { | 508 test_semicolon() async { |
307 await _prepareCompletion( | 509 await _prepareCompletion( |
308 'v = 1', | 510 'v = 1', |
309 ''' | 511 ''' |
310 main() { | 512 main() { |
311 int v = 1 | 513 int v = 1 |
312 } | 514 } |
313 ''', | 515 ''', |
314 atEnd: true); | 516 atEnd: true); |
315 _assertHasChange( | 517 _assertHasChange( |
316 'Add a semicolon and newline', | 518 'Add a semicolon and newline', |
317 ''' | 519 ''' |
318 main() { | 520 main() { |
319 int v = 1; | 521 int v = 1; |
320 //// | 522 //// |
321 } | 523 } |
322 ''', | 524 ''', |
323 (s) => s.lastIndexOf(' ') + ' '.length); | 525 (s) => _afterLast(s, ' ')); |
324 } | |
325 | |
326 void _assertHasChange(String message, String expectedCode, [Function cmp]) { | |
327 if (change.message == message) { | |
328 if (!change.edits.isEmpty) { | |
329 String resultCode = | |
330 SourceEdit.applySequence(testCode, change.edits[0].edits); | |
331 expect(resultCode, expectedCode.replaceAll('////', '')); | |
332 if (cmp != null) { | |
333 int offset = cmp(resultCode); | |
334 expect(change.selection.offset, offset); | |
335 } | |
336 } else { | |
337 if (cmp != null) { | |
338 int offset = cmp(testCode); | |
339 expect(change.selection.offset, offset); | |
340 } | |
341 } | |
342 return; | |
343 } | |
344 fail("Expected to find |$message| but got: " + change.message); | |
345 } | |
346 | |
347 _computeCompletion(int offset) async { | |
348 driver.changeFile(testFile); | |
349 AnalysisResult result = await driver.getResult(testFile); | |
350 StatementCompletionContext context = new StatementCompletionContext( | |
351 testFile, | |
352 result.lineInfo, | |
353 offset, | |
354 testUnit, | |
355 testUnitElement, | |
356 result.errors); | |
357 StatementCompletionProcessor processor = | |
358 new StatementCompletionProcessor(context); | |
359 StatementCompletion completion = await processor.compute(); | |
360 change = completion.change; | |
361 } | |
362 | |
363 _prepareCompletion(String search, String sourceCode, | |
364 {bool atStart: false, bool atEnd: false, int delta: 0}) async { | |
365 testCode = sourceCode.replaceAll('////', ''); | |
366 int offset = findOffset(search); | |
367 if (atStart) { | |
368 delta = 0; | |
369 } else if (atEnd) { | |
370 delta = search.length; | |
371 } | |
372 await _prepareCompletionAt(offset + delta, testCode); | |
373 } | |
374 | |
375 _prepareCompletionAt(int offset, String sourceCode) async { | |
376 verifyNoTestUnitErrors = false; | |
377 await resolveTestUnit(sourceCode); | |
378 await _computeCompletion(offset); | |
379 } | 526 } |
380 } | 527 } |
| 528 |
| 529 @reflectiveTest |
| 530 class _WhileCompletionTest extends StatementCompletionTest { |
| 531 /* |
| 532 The implementation of completion for while-statements is shared with |
| 533 if-statements. Here we check that the wrapper for while-statements |
| 534 functions as expected. The individual test cases are covered by the |
| 535 _IfCompletionTest tests. If the implementation changes then the same |
| 536 set of tests defined for if-statements should be duplicated here. |
| 537 */ |
| 538 test_keywordOnly() async { |
| 539 await _prepareCompletion( |
| 540 'while', |
| 541 ''' |
| 542 main() { |
| 543 while //// |
| 544 } |
| 545 ''', |
| 546 atEnd: true); |
| 547 _assertHasChange( |
| 548 'Complete while-statement', |
| 549 ''' |
| 550 main() { |
| 551 while () { |
| 552 //// |
| 553 } |
| 554 } |
| 555 ''', |
| 556 (s) => _after(s, 'while (')); |
| 557 } |
| 558 } |
OLD | NEW |