blob: 76a76da52150c23b5da1ea99aae3348f348bd56d [file] [log] [blame]
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/plugin/result_merger.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(ResultMergerTest);
});
}
@reflectiveTest
class ResultMergerTest {
//
// The tests in this class should always perform the merge operation twice
// using the same input values in order to ensure that the input values are
// not modified by the merge operation.
//
ResultMerger merger = ResultMerger();
void test_mergeAnalysisErrorFixes() {
AnalysisError createError(int offset) {
var severity = AnalysisErrorSeverity.ERROR;
var type = AnalysisErrorType.HINT;
var location = Location(
'test.dart',
offset,
2,
3,
4,
endLine: 5,
endColumn: 6,
);
return AnalysisError(severity, type, location, '', '');
}
var error1 = createError(10);
var error2 = createError(20);
var error3 = createError(30);
var error4 = createError(40);
var change1 = plugin.PrioritizedSourceChange(1, SourceChange('a'));
var change2 = plugin.PrioritizedSourceChange(2, SourceChange('b'));
var change3 = plugin.PrioritizedSourceChange(3, SourceChange('c'));
var change4 = plugin.PrioritizedSourceChange(4, SourceChange('d'));
var change5 = plugin.PrioritizedSourceChange(5, SourceChange('e'));
var fix1 = plugin.AnalysisErrorFixes(error1, fixes: [change1]);
var fix2 = plugin.AnalysisErrorFixes(error2, fixes: [change2]);
var fix3 = plugin.AnalysisErrorFixes(error2, fixes: [change3]);
var fix4 = plugin.AnalysisErrorFixes(error3, fixes: [change4]);
var fix5 = plugin.AnalysisErrorFixes(error4, fixes: [change5]);
var fix2and3 = plugin.AnalysisErrorFixes(error2, fixes: [change2, change3]);
void runTest() {
expect(
merger.mergeAnalysisErrorFixes([
[fix1, fix2],
[fix3, fix4],
[fix5],
[],
]),
unorderedEquals([fix1, fix2and3, fix4, fix5]),
);
}
runTest();
runTest();
}
void test_mergeAnalysisErrors() {
AnalysisError createError(int offset) {
var severity = AnalysisErrorSeverity.ERROR;
var type = AnalysisErrorType.HINT;
var location = Location(
'test.dart',
offset,
2,
3,
4,
endLine: 5,
endColumn: 6,
);
return AnalysisError(severity, type, location, '', '');
}
var error1 = createError(10);
var error2 = createError(20);
var error3 = createError(30);
var error4 = createError(40);
void runTest() {
expect(
merger.mergeAnalysisErrors([
[error1, error2],
[error3],
[],
[error4],
]),
unorderedEquals([error1, error2, error3, error4]),
);
}
runTest();
runTest();
}
void test_mergeCompletionSuggestions() {
CompletionSuggestion createSuggestion(String completion) =>
CompletionSuggestion(
CompletionSuggestionKind.IDENTIFIER,
50,
completion,
0,
3,
false,
false,
);
var suggestion1 = createSuggestion('a');
var suggestion2 = createSuggestion('b');
var suggestion3 = createSuggestion('c');
var suggestion4 = createSuggestion('d');
void runTest() {
expect(
merger.mergeCompletionSuggestions([
[suggestion1],
[suggestion2, suggestion3, suggestion4],
[],
]),
unorderedEquals([suggestion1, suggestion2, suggestion3, suggestion4]),
);
}
runTest();
runTest();
}
void test_mergeFoldingRegion() {
var kind = FoldingKind.FILE_HEADER;
var region1 = FoldingRegion(kind, 30, 5);
var region2 = FoldingRegion(kind, 0, 4);
var region3 = FoldingRegion(kind, 20, 6);
var region4 = FoldingRegion(kind, 10, 3);
var region5 = FoldingRegion(kind, 2, 6); // overlaps
void runTest() {
expect(
merger.mergeFoldingRegions([
[region1, region2],
[],
[region3],
[region4, region5],
]),
unorderedEquals([region1, region2, region3, region4]),
);
}
runTest();
runTest();
}
void test_mergeHighlightRegions() {
var type = HighlightRegionType.COMMENT_BLOCK;
var region1 = HighlightRegion(type, 30, 5);
var region2 = HighlightRegion(type, 0, 4);
var region3 = HighlightRegion(type, 20, 6);
var region4 = HighlightRegion(type, 10, 3);
void runTest() {
expect(
merger.mergeHighlightRegions([
[region1, region2],
[],
[region3],
[region4],
]),
unorderedEquals([region1, region2, region3, region4]),
);
}
runTest();
runTest();
}
void test_mergeNavigation() {
NavigationTarget target(int fileIndex, int offset) {
return NavigationTarget(
ElementKind.CLASS,
fileIndex,
offset,
1,
0,
0,
codeOffset: offset,
codeLength: 1,
);
}
//
// Create the parameters from the server.
//
var target1_1 = target(0, 1);
var target1_2 = target(0, 2);
var target2_1 = target(1, 3);
var target2_2 = target(1, 4);
var region1_1 = NavigationRegion(10, 4, [0]);
var region1_2 = NavigationRegion(20, 4, [1]);
var region2_1 = NavigationRegion(30, 4, [2]);
var region2_2 = NavigationRegion(40, 4, [3]);
var params1 = AnalysisNavigationParams(
'a.dart',
[region1_1, region1_2, region2_1, region2_2],
[target1_1, target1_2, target2_1, target2_2],
['one.dart', 'two.dart'],
);
//
// Create the parameters from the second plugin.
//
// same file and offset as target 2_2
var target2_3 = target(0, 4);
var target2_4 = target(0, 5);
var target3_1 = target(1, 6);
var target3_2 = target(1, 7);
// same region and target as region2_2
var region2_3 = NavigationRegion(40, 4, [0]);
// same region as region2_2, but a different target
var region2_4 = NavigationRegion(40, 4, [2]);
var region2_5 = NavigationRegion(50, 4, [1]);
var region3_1 = NavigationRegion(60, 4, [2]);
var region3_2 = NavigationRegion(70, 4, [3]);
var params2 = AnalysisNavigationParams(
'a.dart',
[region2_3, region2_4, region2_5, region3_1, region3_2],
[target2_3, target2_4, target3_1, target3_2],
['two.dart', 'three.dart'],
);
var expected = AnalysisNavigationParams(
'a.dart',
[
region1_1,
region1_2,
region2_1,
NavigationRegion(40, 4, [3, 5]), // union of region2_2 and region2_4
NavigationRegion(50, 4, [4]), // region2_5
NavigationRegion(60, 4, [5]), // region3_1
NavigationRegion(70, 4, [6]), // region3_2
],
[
target1_1,
target1_2,
target2_1,
target2_2,
target(1, 5), // target2_4
target(2, 6), // target3_1
target(2, 7), // target3_2
],
['one.dart', 'two.dart', 'three.dart'],
);
void runTest() {
expect(merger.mergeNavigation([params1, params2]), expected);
}
runTest();
runTest();
}
void test_mergeOccurrences() {
var element1 = Element(ElementKind.CLASS, 'e1', 0);
var element2 = Element(ElementKind.CLASS, 'e2', 0);
var element3 = Element(ElementKind.CLASS, 'e3', 0);
var occurrence1 = Occurrences(element1, [1, 2, 4], 2);
var occurrence2 = Occurrences(element2, [5], 2);
var occurrence3 = Occurrences(element1, [2, 3], 2);
var occurrence4 = Occurrences(element3, [8], 2);
var occurrence5 = Occurrences(element2, [6], 2);
var occurrence6 = Occurrences(element3, [7, 9], 2);
var result1 = Occurrences(element1, [1, 2, 3, 4], 2);
var result2 = Occurrences(element2, [5, 6], 2);
var result3 = Occurrences(element3, [7, 8, 9], 2);
void runTest() {
expect(
merger.mergeOccurrences([
[occurrence1, occurrence2],
[],
[occurrence3, occurrence4],
[occurrence5, occurrence6],
]),
unorderedEquals([result1, result2, result3]),
);
}
runTest();
runTest();
}
void test_mergeOutline() {
Element element(ElementKind kind, int offset) {
var location = Location('', offset, 0, 0, 0, endLine: 0, endColumn: 0);
return Element(kind, '', 0, location: location);
}
var element1 = element(ElementKind.CLASS, 100);
var element1_1 = element(ElementKind.METHOD, 110);
var element1_2 = element(ElementKind.METHOD, 120);
var element2 = element(ElementKind.CLASS, 200);
var element2_1 = element(ElementKind.METHOD, 210);
var element2_2 = element(ElementKind.METHOD, 220);
var element3_1 = element(ElementKind.METHOD, 220); // same as 2_2
var element3_2 = element(ElementKind.METHOD, 230);
var element4 = element(ElementKind.CLASS, 300);
var element4_1 = element(ElementKind.METHOD, 310);
//
// Unique, contributed from first plugin.
//
// element1
// - element1_1
// - element1_2
//
var outline1_1 = Outline(element1_1, 0, 0, 0, 0, children: []);
var outline1_2 = Outline(element1_2, 0, 0, 0, 0, children: []);
var outline1 = Outline(
element1,
0,
0,
0,
0,
children: [outline1_1, outline1_2],
);
//
// Same top level element, common child.
//
// element2
// - element2_1
// - element2_2
// element2
// - element3_1
// - element3_2
//
var outline2_1 = Outline(element2_1, 0, 0, 0, 0, children: []);
var outline2_2 = Outline(element2_2, 0, 0, 0, 0, children: []);
var outline3_1 = Outline(element3_1, 0, 0, 0, 0, children: []);
var outline3_2 = Outline(element3_2, 0, 0, 0, 0, children: []);
var outline2 = Outline(
element2,
0,
0,
0,
0,
children: [outline2_1, outline2_2],
);
var outline3 = Outline(
element2,
0,
0,
0,
0,
children: [outline3_1, outline3_2],
);
var outline2and3 = Outline(
element2,
0,
0,
0,
0,
children: [outline2_1, outline2_2, outline3_2],
);
//
// Unique, contributed from second plugin.
//
// element4
// - element4_1
//
var outline4_1 = Outline(element4_1, 0, 0, 0, 0, children: []);
var outline4 = Outline(element4, 0, 0, 0, 0, children: [outline4_1]);
void runTest() {
expect(
merger.mergeOutline([
[outline1, outline2],
[],
[outline3, outline4],
]),
unorderedEquals([outline1, outline2and3, outline4]),
);
}
runTest();
runTest();
}
void test_mergePrioritizedSourceChanges() {
var kind1 = plugin.PrioritizedSourceChange(1, SourceChange(''));
var kind2 = plugin.PrioritizedSourceChange(1, SourceChange(''));
var kind3 = plugin.PrioritizedSourceChange(1, SourceChange(''));
var kind4 = plugin.PrioritizedSourceChange(1, SourceChange(''));
void runTest() {
expect(
merger.mergePrioritizedSourceChanges([
[kind3, kind2],
[],
[kind4],
[kind1],
]),
unorderedEquals([kind1, kind2, kind3, kind4]),
);
}
runTest();
runTest();
}
void test_mergeRefactoringFeedbacks_convertGetterToMethodFeedback() {
RefactoringFeedback feedback1 = ConvertGetterToMethodFeedback();
RefactoringFeedback feedback2 = ConvertGetterToMethodFeedback();
void runTest() {
expect(
merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
equals(feedback1),
);
}
runTest();
runTest();
}
void test_mergeRefactoringFeedbacks_convertMethodToGetterFeedback() {
RefactoringFeedback feedback1 = ConvertMethodToGetterFeedback();
RefactoringFeedback feedback2 = ConvertMethodToGetterFeedback();
void runTest() {
expect(
merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
equals(feedback1),
);
}
runTest();
runTest();
}
void
test_mergeRefactoringFeedbacks_extractLocalVariableFeedback_addEverything() {
var names1 = <String>['a', 'b', 'c'];
var offsets1 = <int>[10, 20];
var lengths1 = <int>[4, 5];
var coveringOffsets1 = <int>[100, 150, 200];
var coveringLengths1 = <int>[200, 100, 20];
RefactoringFeedback feedback1 = ExtractLocalVariableFeedback(
names1,
offsets1,
lengths1,
coveringExpressionOffsets: coveringOffsets1,
coveringExpressionLengths: coveringLengths1,
);
var names2 = <String>['c', 'd'];
var offsets2 = <int>[30];
var lengths2 = <int>[6];
var coveringOffsets2 = <int>[210];
var coveringLengths2 = <int>[5];
RefactoringFeedback feedback2 = ExtractLocalVariableFeedback(
names2,
offsets2,
lengths2,
coveringExpressionOffsets: coveringOffsets2,
coveringExpressionLengths: coveringLengths2,
);
var resultNames = <String>['a', 'b', 'c', 'd'];
var resultOffsets = List<int>.from(offsets1)..addAll(offsets2);
var resultLengths = List<int>.from(lengths1)..addAll(lengths2);
var resultCoveringOffsets = List<int>.from(coveringOffsets1)
..addAll(coveringOffsets2);
var resultCoveringLengths = List<int>.from(coveringLengths1)
..addAll(coveringLengths2);
RefactoringFeedback result = ExtractLocalVariableFeedback(
resultNames,
resultOffsets,
resultLengths,
coveringExpressionOffsets: resultCoveringOffsets,
coveringExpressionLengths: resultCoveringLengths,
);
void runTest() {
expect(
merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
equals(result),
);
}
runTest();
runTest();
}
void
test_mergeRefactoringFeedbacks_extractLocalVariableFeedback_addOffsetsAndLengths() {
var names1 = <String>['a', 'b', 'c'];
var offsets1 = <int>[10, 20];
var lengths1 = <int>[4, 5];
var coveringOffsets1 = <int>[100, 150, 200];
var coveringLengths1 = <int>[200, 100, 20];
RefactoringFeedback feedback1 = ExtractLocalVariableFeedback(
names1,
offsets1,
lengths1,
coveringExpressionOffsets: coveringOffsets1,
coveringExpressionLengths: coveringLengths1,
);
var names2 = <String>[];
var offsets2 = <int>[30];
var lengths2 = <int>[6];
RefactoringFeedback feedback2 = ExtractLocalVariableFeedback(
names2,
offsets2,
lengths2,
);
var resultOffsets = List<int>.from(offsets1)..addAll(offsets2);
var resultLengths = List<int>.from(lengths1)..addAll(lengths2);
RefactoringFeedback result = ExtractLocalVariableFeedback(
names1,
resultOffsets,
resultLengths,
coveringExpressionOffsets: coveringOffsets1,
coveringExpressionLengths: coveringLengths1,
);
void runTest() {
expect(
merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
equals(result),
);
}
runTest();
runTest();
}
void
test_mergeRefactoringFeedbacks_extractLocalVariableFeedback_noCoverings() {
var names1 = <String>['a', 'b', 'c'];
var offsets1 = <int>[10, 20];
var lengths1 = <int>[4, 5];
RefactoringFeedback feedback1 = ExtractLocalVariableFeedback(
names1,
offsets1,
lengths1,
);
var names2 = <String>[];
var offsets2 = <int>[30];
var lengths2 = <int>[6];
RefactoringFeedback feedback2 = ExtractLocalVariableFeedback(
names2,
offsets2,
lengths2,
);
var resultOffsets = List<int>.from(offsets1)..addAll(offsets2);
var resultLengths = List<int>.from(lengths1)..addAll(lengths2);
RefactoringFeedback result = ExtractLocalVariableFeedback(
names1,
resultOffsets,
resultLengths,
);
void runTest() {
expect(
merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
equals(result),
);
}
runTest();
runTest();
}
void test_mergeRefactoringFeedbacks_extractMethodFeedback() {
var offset1 = 20;
var length1 = 5;
var returnType1 = 'int';
var names1 = <String>['a', 'b', 'c'];
var canCreateGetter1 = false;
var parameters1 = <RefactoringMethodParameter>[];
var offsets1 = <int>[10, 20];
var lengths1 = <int>[4, 5];
RefactoringFeedback feedback1 = ExtractMethodFeedback(
offset1,
length1,
returnType1,
names1,
canCreateGetter1,
parameters1,
offsets1,
lengths1,
);
var names2 = <String>['c', 'd'];
var canCreateGetter2 = true;
var parameters2 = <RefactoringMethodParameter>[];
var offsets2 = <int>[30];
var lengths2 = <int>[6];
RefactoringFeedback feedback2 = ExtractMethodFeedback(
0,
0,
'',
names2,
canCreateGetter2,
parameters2,
offsets2,
lengths2,
);
var resultNames = <String>['a', 'b', 'c', 'd'];
var resultOffsets = List<int>.from(offsets1)..addAll(offsets2);
var resultLengths = List<int>.from(lengths1)..addAll(lengths2);
RefactoringFeedback result = ExtractMethodFeedback(
offset1,
length1,
returnType1,
resultNames,
false,
parameters1,
resultOffsets,
resultLengths,
);
void runTest() {
expect(
merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
equals(result),
);
}
runTest();
runTest();
}
void test_mergeRefactoringFeedbacks_inlineLocalVariableFeedback() {
RefactoringFeedback feedback1 = InlineLocalVariableFeedback('a', 2);
RefactoringFeedback feedback2 = InlineLocalVariableFeedback('a', 3);
RefactoringFeedback result = InlineLocalVariableFeedback('a', 5);
void runTest() {
expect(
merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
equals(result),
);
}
runTest();
runTest();
}
void test_mergeRefactoringFeedbacks_inlineMethodFeedback() {
RefactoringFeedback feedback1 = InlineMethodFeedback('a', false);
RefactoringFeedback feedback2 = InlineMethodFeedback('a', false);
void runTest() {
expect(
merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
equals(feedback1),
);
}
runTest();
runTest();
}
void test_mergeRefactoringFeedbacks_moveFileFeedback() {
RefactoringFeedback feedback1 = MoveFileFeedback();
RefactoringFeedback feedback2 = MoveFileFeedback();
void runTest() {
expect(
merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
equals(feedback1),
);
}
runTest();
runTest();
}
void test_mergeRefactoringFeedbacks_renameFeedback() {
RefactoringFeedback feedback1 = RenameFeedback(10, 0, '', '');
RefactoringFeedback feedback2 = RenameFeedback(20, 0, '', '');
void runTest() {
expect(
merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
equals(feedback1),
);
}
runTest();
runTest();
}
void test_mergeRefactoringKinds() {
var kind1 = RefactoringKind.CONVERT_GETTER_TO_METHOD;
var kind2 = RefactoringKind.EXTRACT_LOCAL_VARIABLE;
var kind3 = RefactoringKind.INLINE_LOCAL_VARIABLE;
var kind4 = RefactoringKind.MOVE_FILE;
var kind5 = RefactoringKind.EXTRACT_LOCAL_VARIABLE;
void runTest() {
expect(
merger.mergeRefactoringKinds([
[kind1, kind2],
[kind3],
[],
[kind4, kind5],
]),
unorderedEquals([kind1, kind2, kind3, kind4]),
);
}
runTest();
runTest();
}
void test_mergeRefactorings() {
RefactoringProblem problem(String message) =>
RefactoringProblem(RefactoringProblemSeverity.ERROR, message);
var problem1 = problem('1');
var problem2 = problem('2');
var problem3 = problem('3');
var problem4 = problem('4');
var problem5 = problem('5');
var problem6 = problem('6');
var initialProblems1 = <RefactoringProblem>[problem1, problem2];
var optionsProblems1 = <RefactoringProblem>[problem3];
var finalProblems1 = <RefactoringProblem>[problem4];
RefactoringFeedback feedback1 = RenameFeedback(10, 0, '', '');
var edit1 = SourceFileEdit(
'file1.dart',
11,
edits: <SourceEdit>[
SourceEdit(12, 2, 'w', id: 'e1'),
SourceEdit(13, 3, 'x'),
],
);
var change1 = SourceChange('c1', edits: <SourceFileEdit>[edit1]);
var potentialEdits1 = <String>['e1'];
var result1 = EditGetRefactoringResult(
initialProblems1,
optionsProblems1,
finalProblems1,
feedback: feedback1,
change: change1,
potentialEdits: potentialEdits1,
);
var initialProblems2 = <RefactoringProblem>[problem5];
var optionsProblems2 = <RefactoringProblem>[];
var finalProblems2 = <RefactoringProblem>[problem6];
RefactoringFeedback feedback2 = RenameFeedback(20, 0, '', '');
var edit2 = SourceFileEdit(
'file2.dart',
21,
edits: <SourceEdit>[
SourceEdit(12, 2, 'y', id: 'e2'),
SourceEdit(13, 3, 'z'),
],
);
var change2 = SourceChange('c2', edits: <SourceFileEdit>[edit2]);
var potentialEdits2 = <String>['e2'];
var result2 = EditGetRefactoringResult(
initialProblems2,
optionsProblems2,
finalProblems2,
feedback: feedback2,
change: change2,
potentialEdits: potentialEdits2,
);
var mergedInitialProblems = <RefactoringProblem>[
problem1,
problem2,
problem5,
];
var mergedOptionsProblems = <RefactoringProblem>[problem3];
var mergedFinalProblems = <RefactoringProblem>[problem4, problem6];
var mergedChange = SourceChange(
'c1',
edits: <SourceFileEdit>[edit1, edit2],
);
var mergedPotentialEdits = <String>['e1', 'e2'];
var mergedResult = EditGetRefactoringResult(
mergedInitialProblems,
mergedOptionsProblems,
mergedFinalProblems,
feedback: merger.mergeRefactoringFeedbacks([feedback1, feedback2]),
change: mergedChange,
potentialEdits: mergedPotentialEdits,
);
void runTest() {
expect(merger.mergeRefactorings([result1, result2]), mergedResult);
}
runTest();
runTest();
}
void test_mergeSourceChanges() {
var kind1 = SourceChange('');
var kind2 = SourceChange('');
var kind3 = SourceChange('');
var kind4 = SourceChange('');
void runTest() {
expect(
merger.mergeSourceChanges([
[kind1, kind2],
[],
[kind3],
[kind4],
]),
unorderedEquals([kind1, kind2, kind3, kind4]),
);
}
runTest();
runTest();
}
void test_overlaps_false_nested_left() {
expect(merger.overlaps(3, 5, 1, 7, allowNesting: true), isFalse);
}
void test_overlaps_false_nested_right() {
expect(merger.overlaps(1, 7, 3, 5, allowNesting: true), isFalse);
}
void test_overlaps_false_onLeft() {
expect(merger.overlaps(1, 3, 5, 7), isFalse);
}
void test_overlaps_false_onRight() {
expect(merger.overlaps(5, 7, 1, 3), isFalse);
}
void test_overlaps_true_nested_left() {
expect(merger.overlaps(3, 5, 1, 7), isTrue);
}
void test_overlaps_true_nested_right() {
expect(merger.overlaps(1, 7, 3, 5), isTrue);
}
void test_overlaps_true_onLeft() {
expect(merger.overlaps(1, 5, 3, 7), isTrue);
}
void test_overlaps_true_onRight() {
expect(merger.overlaps(3, 7, 1, 5), isTrue);
}
}