Index: pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart |
diff --git a/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart b/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart |
index 1b99cfed2f6992a0819587c184cf7ad930e2e456..e6d4077c69988fc975ead13829195c295242767c 100644 |
--- a/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart |
+++ b/pkg/analysis_server/test/services/completion/statement/statement_completion_test.dart |
@@ -14,17 +14,84 @@ import '../../../abstract_single_unit.dart'; |
main() { |
defineReflectiveSuite(() { |
- defineReflectiveTests(StatementCompletionTest); |
+ defineReflectiveTests(_DoCompletionTest); |
+ defineReflectiveTests(_ForCompletionTest); |
+ defineReflectiveTests(_IfCompletionTest); |
+ defineReflectiveTests(_SimpleCompletionTest); |
+ defineReflectiveTests(_WhileCompletionTest); |
}); |
} |
-@reflectiveTest |
class StatementCompletionTest extends AbstractSingleUnitTest { |
SourceChange change; |
bool get enableNewAnalysisDriver => true; |
- test_completeDoEmptyCondition() async { |
+ int _after(String source, String match) => |
+ source.indexOf(match) + match.length; |
+ |
+ int _afterLast(String source, String match) => |
+ source.lastIndexOf(match) + match.length; |
+ |
+ void _assertHasChange(String message, String expectedCode, [Function cmp]) { |
+ if (change.message == message) { |
+ if (!change.edits.isEmpty) { |
+ String resultCode = |
+ SourceEdit.applySequence(testCode, change.edits[0].edits); |
+ expect(resultCode, expectedCode.replaceAll('////', '')); |
+ if (cmp != null) { |
+ int offset = cmp(resultCode); |
+ expect(change.selection.offset, offset); |
+ } |
+ } else { |
+ if (cmp != null) { |
+ int offset = cmp(testCode); |
+ expect(change.selection.offset, offset); |
+ } |
+ } |
+ return; |
+ } |
+ fail("Expected to find |$message| but got: " + change.message); |
+ } |
+ |
+ _computeCompletion(int offset) async { |
+ driver.changeFile(testFile); |
+ AnalysisResult result = await driver.getResult(testFile); |
+ StatementCompletionContext context = new StatementCompletionContext( |
+ testFile, |
+ result.lineInfo, |
+ offset, |
+ testUnit, |
+ testUnitElement, |
+ result.errors); |
+ StatementCompletionProcessor processor = |
+ new StatementCompletionProcessor(context); |
+ StatementCompletion completion = await processor.compute(); |
+ change = completion.change; |
+ } |
+ |
+ _prepareCompletion(String search, String sourceCode, |
+ {bool atStart: false, bool atEnd: false, int delta: 0}) async { |
+ testCode = sourceCode.replaceAll('////', ''); |
+ int offset = findOffset(search); |
+ if (atStart) { |
+ delta = 0; |
+ } else if (atEnd) { |
+ delta = search.length; |
+ } |
+ await _prepareCompletionAt(offset + delta, testCode); |
+ } |
+ |
+ _prepareCompletionAt(int offset, String sourceCode) async { |
+ verifyNoTestUnitErrors = false; |
+ await resolveTestUnit(sourceCode); |
+ await _computeCompletion(offset); |
+ } |
+} |
+ |
+@reflectiveTest |
+class _DoCompletionTest extends StatementCompletionTest { |
+ test_emptyCondition() async { |
await _prepareCompletion( |
'while ()', |
''' |
@@ -42,10 +109,10 @@ main() { |
} while (); |
} |
''', |
- (s) => s.indexOf('while (') + 'while ('.length); |
+ (s) => _after(s, 'while (')); |
} |
- test_completeDoKeywordOnly() async { |
+ test_keywordOnly() async { |
await _prepareCompletion( |
'do', |
''' |
@@ -63,10 +130,10 @@ main() { |
} while (); |
} |
''', |
- (s) => s.indexOf('while (') + 'while ('.length); |
+ (s) => _after(s, 'while (')); |
} |
- test_completeDoNoBody() async { |
+ test_noBody() async { |
await _prepareCompletion( |
'do', |
''' |
@@ -85,10 +152,10 @@ main() { |
} while (); |
} |
''', |
- (s) => s.indexOf('while (') + 'while ('.length); |
+ (s) => _after(s, 'while (')); |
} |
- test_completeDoNoCondition() async { |
+ test_noCondition() async { |
await _prepareCompletion( |
'while', |
''' |
@@ -106,10 +173,10 @@ main() { |
} while (); |
} |
''', |
- (s) => s.indexOf('while (') + 'while ('.length); |
+ (s) => _after(s, 'while (')); |
} |
- test_completeDoNoWhile() async { |
+ test_noWhile() async { |
await _prepareCompletion( |
'}', |
''' |
@@ -127,10 +194,163 @@ main() { |
} while (); |
} |
''', |
- (s) => s.indexOf('while (') + 'while ('.length); |
+ (s) => _after(s, 'while (')); |
+ } |
+} |
+ |
+@reflectiveTest |
+class _ForCompletionTest extends StatementCompletionTest { |
+ test_emptyCondition() async { |
+ await _prepareCompletion( |
+ '}', |
+ ''' |
+main() { |
+ for (int i = 0;) { |
+ } |
+} |
+''', |
+ atEnd: true); |
+ _assertHasChange( |
+ 'Complete for-statement', |
+ ''' |
+main() { |
+ for (int i = 0; ) { |
+ } |
+} |
+''', |
+ (s) => _after(s, '0; ')); |
+ } |
+ |
+ test_emptyInitializers() async { |
+ await _prepareCompletion( |
+ '}', |
+ ''' |
+main() { |
+ for () { |
+ } |
+} |
+''', |
+ atEnd: true); |
+ _assertHasChange( |
+ 'Complete for-statement', |
+ ''' |
+main() { |
+ for () { |
+ } |
+} |
+''', |
+ (s) => _after(s, 'for (')); |
+ } |
+ |
+ test_emptyInitializersEmptyCondition() async { |
+ await _prepareCompletion( |
+ '}', |
+ ''' |
+main() { |
+ for (;/**/) { |
+ } |
+} |
+''', |
+ atEnd: true); |
+ _assertHasChange( |
+ 'Complete for-statement', |
+ ''' |
+main() { |
+ for (;/**/) { |
+ } |
+} |
+''', |
+ (s) => _after(s, '/**/')); |
} |
- test_completeIfAfterCondition_BAD() async { |
+ test_emptyParts() async { |
+ await _prepareCompletion( |
+ ';)', |
+ ''' |
+main() { |
+ for (;;) |
+} |
+''', |
+ atEnd: true); |
+ _assertHasChange( |
+ 'Complete for-statement', |
+ ''' |
+main() { |
+ for (;;) { |
+ //// |
+ } |
+} |
+''', |
+ (s) => _after(s, ' ')); |
+ } |
+ |
+ test_emptyUpdaters() async { |
+ await _prepareCompletion( |
+ '}', |
+ ''' |
+main() { |
+ for (int i = 0; i < 10 /**/) { |
+ } |
+} |
+''', |
+ atEnd: true); |
+ _assertHasChange( |
+ 'Complete for-statement', |
+ ''' |
+main() { |
+ for (int i = 0; i < 10 /**/; ) { |
+ } |
+} |
+''', |
+ (s) => _after(s, '10 /**/; ')); |
+ } |
+ |
+ test_keywordOnly() async { |
+ await _prepareCompletion( |
+ 'for', |
+ ''' |
+main() { |
+ for |
+} |
+''', |
+ atEnd: true); |
+ _assertHasChange( |
+ 'Complete for-statement', |
+ ''' |
+main() { |
+ for () { |
+ //// |
+ } |
+} |
+''', |
+ (s) => _after(s, 'for (')); |
+ } |
+ |
+ test_missingLeftSeparator() async { |
+ await _prepareCompletion( |
+ '}', |
+ ''' |
+main() { |
+ for (int i = 0) { |
+ } |
+} |
+''', |
+ atEnd: true); |
+ _assertHasChange( |
+ 'Complete for-statement', |
+ ''' |
+main() { |
+ for (int i = 0; ) { |
+ } |
+} |
+''', |
+ (s) => _after(s, '0; ')); |
+ } |
+} |
+ |
+@reflectiveTest |
+class _IfCompletionTest extends StatementCompletionTest { |
+ test_afterCondition_BAD() async { |
// TODO(messick): Fix the code to make this like test_completeIfWithCondition. |
// Recap: Finding the node at the selectionOffset returns the block, not the |
// if-statement. Need to understand if that only happens when the if-statement |
@@ -153,10 +373,10 @@ main() { |
} |
} |
''', |
- (s) => s.indexOf('if (true) ') + 'if (true) '.length); |
+ (s) => _after(s, 'if (true) ')); |
} |
- test_completeIfEmptyCondition() async { |
+ test_emptyCondition() async { |
await _prepareCompletion( |
'if ()', |
''' |
@@ -174,10 +394,10 @@ main() { |
} |
} |
''', |
- (s) => s.indexOf('if (') + 'if ('.length); |
+ (s) => _after(s, 'if (')); |
} |
- test_completeIfKeywordOnly() async { |
+ test_keywordOnly() async { |
await _prepareCompletion( |
'if', |
''' |
@@ -195,10 +415,10 @@ main() { |
} |
} |
''', |
- (s) => s.indexOf('if (') + 'if ('.length); |
+ (s) => _after(s, 'if (')); |
} |
- test_completeIfWithCondition() async { |
+ test_withCondition() async { |
await _prepareCompletion( |
'if (tr', // Trigger completion from within expression. |
''' |
@@ -216,10 +436,10 @@ main() { |
} |
} |
''', |
- (s) => s.indexOf(' ') + ' '.length); |
+ (s) => _after(s, ' ')); |
} |
- test_completeIfWithElse_BAD() async { |
+ test_withElse_BAD() async { |
await _prepareCompletion( |
'if ()', |
''' |
@@ -239,10 +459,10 @@ main() { |
} |
} |
''', |
- (s) => s.indexOf('if ()') + 'if ()'.length); |
+ (s) => _after(s, 'if ()')); |
} |
- test_completeIfWithinEmptyCondition() async { |
+ test_withinEmptyCondition() async { |
await _prepareCompletion( |
'if (', |
''' |
@@ -260,31 +480,13 @@ main() { |
} |
} |
''', |
- (s) => s.indexOf('if (') + 'if ('.length); |
+ (s) => _after(s, 'if (')); |
} |
- |
- test_completeWhileKeywordOnly() async { |
- await _prepareCompletion( |
- 'while', |
- ''' |
-main() { |
- while //// |
} |
-''', |
- atEnd: true); |
- _assertHasChange( |
- 'Complete while-statement', |
- ''' |
-main() { |
- while () { |
- //// |
- } |
-} |
-''', |
- (s) => s.indexOf('while (') + 'while ('.length); |
- } |
- test_simpleEnter() async { |
+@reflectiveTest |
+class _SimpleCompletionTest extends StatementCompletionTest { |
+ test_enter() async { |
await _prepareCompletion( |
'v = 1;', |
''' |
@@ -303,7 +505,7 @@ main() { |
'''); |
} |
- test_simpleSemicolon() async { |
+ test_semicolon() async { |
await _prepareCompletion( |
'v = 1', |
''' |
@@ -320,61 +522,37 @@ main() { |
//// |
} |
''', |
- (s) => s.lastIndexOf(' ') + ' '.length); |
- } |
- |
- void _assertHasChange(String message, String expectedCode, [Function cmp]) { |
- if (change.message == message) { |
- if (!change.edits.isEmpty) { |
- String resultCode = |
- SourceEdit.applySequence(testCode, change.edits[0].edits); |
- expect(resultCode, expectedCode.replaceAll('////', '')); |
- if (cmp != null) { |
- int offset = cmp(resultCode); |
- expect(change.selection.offset, offset); |
- } |
- } else { |
- if (cmp != null) { |
- int offset = cmp(testCode); |
- expect(change.selection.offset, offset); |
- } |
- } |
- return; |
- } |
- fail("Expected to find |$message| but got: " + change.message); |
- } |
- |
- _computeCompletion(int offset) async { |
- driver.changeFile(testFile); |
- AnalysisResult result = await driver.getResult(testFile); |
- StatementCompletionContext context = new StatementCompletionContext( |
- testFile, |
- result.lineInfo, |
- offset, |
- testUnit, |
- testUnitElement, |
- result.errors); |
- StatementCompletionProcessor processor = |
- new StatementCompletionProcessor(context); |
- StatementCompletion completion = await processor.compute(); |
- change = completion.change; |
+ (s) => _afterLast(s, ' ')); |
} |
+} |
- _prepareCompletion(String search, String sourceCode, |
- {bool atStart: false, bool atEnd: false, int delta: 0}) async { |
- testCode = sourceCode.replaceAll('////', ''); |
- int offset = findOffset(search); |
- if (atStart) { |
- delta = 0; |
- } else if (atEnd) { |
- delta = search.length; |
- } |
- await _prepareCompletionAt(offset + delta, testCode); |
+@reflectiveTest |
+class _WhileCompletionTest extends StatementCompletionTest { |
+ /* |
+ The implementation of completion for while-statements is shared with |
+ if-statements. Here we check that the wrapper for while-statements |
+ functions as expected. The individual test cases are covered by the |
+ _IfCompletionTest tests. If the implementation changes then the same |
+ set of tests defined for if-statements should be duplicated here. |
+ */ |
+ test_keywordOnly() async { |
+ await _prepareCompletion( |
+ 'while', |
+ ''' |
+main() { |
+ while //// |
+} |
+''', |
+ atEnd: true); |
+ _assertHasChange( |
+ 'Complete while-statement', |
+ ''' |
+main() { |
+ while () { |
+ //// |
} |
- |
- _prepareCompletionAt(int offset, String sourceCode) async { |
- verifyNoTestUnitErrors = false; |
- await resolveTestUnit(sourceCode); |
- await _computeCompletion(offset); |
+} |
+''', |
+ (s) => _after(s, 'while (')); |
} |
} |