blob: 4fa30e30e809c300f7fa5d8bbacc7b7cbe280da1 [file] [log] [blame]
// Copyright (c) 2014, 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/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analysis_server/src/services/search/search_engine_internal.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/test_utilities/platform.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
show RefactoringProblemSeverity, SourceChange, SourceEdit;
import 'package:test/test.dart';
import '../../abstract_single_unit.dart';
int findIdentifierLength(String search) {
var length = 0;
while (length < search.length) {
var c = search.codeUnitAt(length);
if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) ||
c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) ||
c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) {
break;
}
length++;
}
return length;
}
/// The base class for all [Refactoring] tests.
abstract class RefactoringTest extends AbstractSingleUnitTest {
late SearchEngine searchEngine;
late SourceChange refactoringChange;
Refactoring get refactoring;
/// Asserts that [refactoringChange] contains a [FileEdit] for the file
/// with the given [path], and it results the [expectedCode].
void assertFileChangeResult(String path, String expectedCode) {
if (useLineEndingsForPlatform) {
expectedCode = normalizeNewlinesForPlatform(expectedCode);
}
// prepare FileEdit
var fileEdit = refactoringChange.getFileEdit(convertPath(path));
if (fileEdit == null) {
fail('No file edit for $path');
}
// validate resulting code
var file = getFile(path);
var ini = file.readAsStringSync();
var actualCode = SourceEdit.applySequence(ini, fileEdit.edits);
expect(actualCode, expectedCode);
}
/// Asserts that [refactoringChange] does not contain a [FileEdit] for the
/// file with the given [path].
void assertNoFileChange(String path) {
var fileEdit = refactoringChange.getFileEdit(path);
expect(fileEdit, isNull);
}
/// Asserts that [refactoring] initial/final conditions status is OK.
Future assertRefactoringConditionsOK() async {
var status = await refactoring.checkInitialConditions();
assertRefactoringStatusOK(status);
status = await refactoring.checkFinalConditions();
assertRefactoringStatusOK(status);
}
/// Asserts that [refactoring] final conditions status is OK.
Future assertRefactoringFinalConditionsOK() async {
var status = await refactoring.checkFinalConditions();
assertRefactoringStatusOK(status);
}
/// Asserts that [status] has expected severity and message.
void assertRefactoringStatus(
RefactoringStatus status, RefactoringProblemSeverity? expectedSeverity,
{String? expectedMessage,
SourceRange? expectedContextRange,
String? expectedContextSearch}) {
expect(status.severity, expectedSeverity, reason: status.toString());
if (expectedSeverity != null) {
var problem = status.problem!;
expect(problem.severity, expectedSeverity);
if (expectedMessage != null) {
expect(problem.message, expectedMessage);
}
if (expectedContextRange != null) {
var location = problem.location!;
expect(location.offset, expectedContextRange.offset);
expect(location.length, expectedContextRange.length);
}
if (expectedContextSearch != null) {
var location = problem.location!;
var expectedOffset = findOffset(expectedContextSearch);
var expectedLength = findIdentifierLength(expectedContextSearch);
expect(location.offset, expectedOffset);
expect(location.length, expectedLength);
}
}
}
/// Asserts that [refactoring] status is OK.
void assertRefactoringStatusOK(RefactoringStatus status) {
assertRefactoringStatus(status, null);
}
/// Checks that all conditions of [refactoring] are OK and the result of
/// applying the [Change] to [testUnit] is [expectedCode].
Future assertSuccessfulRefactoring(String expectedCode) async {
await assertRefactoringConditionsOK();
var change = await refactoring.createChange();
refactoringChange = change;
assertTestChangeResult(expectedCode);
}
/// Asserts that [refactoringChange] contains a [FileEdit] for [testFile], and
/// it results the [expectedCode].
void assertTestChangeResult(String expectedCode) {
if (useLineEndingsForPlatform) {
expectedCode = normalizeNewlinesForPlatform(expectedCode);
}
// prepare FileEdit
var fileEdit = refactoringChange.getFileEdit(testFile);
if (fileEdit == null) {
fail('No file edit for $testFile');
}
// validate resulting code
var actualCode = SourceEdit.applySequence(testCode, fileEdit.edits);
expect(actualCode, expectedCode);
}
Future<void> indexTestUnit(String code) async {
await resolveTestCode(code);
}
Future<void> indexUnit(String file, String code) async {
addSource(file, code);
}
@override
void verifyCreatedCollection() {
super.verifyCreatedCollection();
// TODO(dantup): Get these tests passing with either line ending and change this to true.
useLineEndingsForPlatform = false;
searchEngine = SearchEngineImpl([
driverFor(testPackageRootPath),
]);
}
}