blob: bc26d3ea145ead1e576c02d7de73539710cfc171 [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.
library test.domain.analysis.abstract;
import 'dart:async';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/domain_analysis.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/resource.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:unittest/unittest.dart';
import 'mocks.dart';
main() {
}
/**
* An abstract base for all 'analysis' domain tests.
*/
class AbstractAnalysisTest {
MockServerChannel serverChannel;
MemoryResourceProvider resourceProvider;
AnalysisServer server;
AnalysisDomainHandler handler;
Map<String, List<String>> analysisSubscriptions = {};
String projectPath = '/project';
String testFile = '/project/bin/test.dart';
String testCode;
// Map<String, List<AnalysisError>> filesErrors = {};
// Map<String, List<Map<String, Object>>> filesHighlights = {};
// Map<String, List<Map<String, Object>>> filesNavigation = {};
AbstractAnalysisTest() {
}
void setUp() {
serverChannel = new MockServerChannel();
resourceProvider = new MemoryResourceProvider();
server = new AnalysisServer(serverChannel, resourceProvider);
handler = new AnalysisDomainHandler(server);
// listen for notifications
Stream<Notification> notificationStream = serverChannel.notificationController.stream;
notificationStream.listen((Notification notification) {
processNotification(notification);
});
// create an empty project
_createEmptyProject();
}
void addAnalysisSubscription(AnalysisService service, String file) {
// add file to subscription
var files = analysisSubscriptions[service.name];
if (files == null) {
files = <String>[];
analysisSubscriptions[service.name] = files;
}
files.add(file);
// set subscriptions
Request request = new Request('0', METHOD_SET_ANALYSIS_SUBSCRIPTIONS);
request.setParameter(SUBSCRIPTIONS, analysisSubscriptions);
handleSuccessfulRequest(request);
}
void tearDown() {
server.done();
handler = null;
server = null;
resourceProvider = null;
serverChannel = null;
}
void processNotification(Notification notification) {
// if (notification.event == NOTIFICATION_ERRORS) {
// String file = notification.getParameter(FILE);
// List<Map<String, Object>> errorMaps = notification.getParameter(ERRORS);
// filesErrors[file] = errorMaps.map(jsonToAnalysisError).toList();
// }
// if (notification.event == NOTIFICATION_HIGHLIGHTS) {
// String file = notification.getParameter(FILE);
// filesHighlights[file] = notification.getParameter(REGIONS);
// }
// if (notification.event == NOTIFICATION_NAVIGATION) {
// String file = notification.getParameter(FILE);
// filesNavigation[file] = notification.getParameter(REGIONS);
// }
}
/**
* Returns a [Future] that completes when the [AnalysisServer] finishes
* all its scheduled tasks.
*/
Future waitForTasksFinished() {
return waitForServerOperationsPerformed(server);
}
/**
* Returns the offset of [search] in [testCode].
* Fails if not found.
*/
int findFileOffset(String path, String search) {
File file = resourceProvider.getResource(path) as File;
String code = file.createSource(UriKind.FILE_URI).contents.data;
int offset = code.indexOf(search);
expect(offset, isNot(-1), reason: '"$search" in\n$code');
return offset;
}
/**
* Returns the offset of [search] in [testCode].
* Fails if not found.
*/
int findOffset(String search) {
int offset = testCode.indexOf(search);
expect(offset, isNot(-1));
return offset;
}
// /**
// * Returns [AnalysisError]s recorded for the given [file].
// * May be empty, but not `null`.
// */
// List<AnalysisError> getErrors(String file) {
// List<AnalysisError> errors = filesErrors[file];
// if (errors != null) {
// return errors;
// }
// return <AnalysisError>[];
// }
//
// /**
// * Returns highlights recorded for the given [file].
// * May be empty, but not `null`.
// */
// List<Map<String, Object>> getHighlights(String file) {
// List<Map<String, Object>> highlights = filesHighlights[file];
// if (highlights != null) {
// return highlights;
// }
// return [];
// }
//
// /**
// * Returns navigation regions recorded for the given [file].
// * May be empty, but not `null`.
// */
// List<Map<String, Object>> getNavigation(String file) {
// List<Map<String, Object>> navigation = filesNavigation[file];
// if (navigation != null) {
// return navigation;
// }
// return [];
// }
//
// /**
// * Returns [AnalysisError]s recorded for the [testFile].
// * May be empty, but not `null`.
// */
// List<AnalysisError> getTestErrors() {
// return getErrors(testFile);
// }
//
// /**
// * Returns highlights recorded for the given [testFile].
// * May be empty, but not `null`.
// */
// List<Map<String, Object>> getTestHighlights() {
// return getHighlights(testFile);
// }
//
// /**
// * Returns navigation information recorded for the given [testFile].
// * May be empty, but not `null`.
// */
// List<Map<String, Object>> getTestNavigation() {
// return getNavigation(testFile);
// }
/**
* Creates an empty project `/project/`.
*/
void _createEmptyProject() {
resourceProvider.newFolder(projectPath);
Request request = new Request('0', METHOD_SET_ANALYSIS_ROOTS);
request.setParameter(INCLUDED, [projectPath]);
request.setParameter(EXCLUDED, []);
handleSuccessfulRequest(request);
}
// /**
// * Creates a project with a single Dart file `/project/bin/test.dart` with
// * the given [code].
// */
// void createSingleFileProject(code) {
// this.testCode = _getCodeString(code);
// resourceProvider.newFolder('/project');
// resourceProvider.newFile(testFile, testCode);
// Request request = new Request('0', METHOD_SET_ANALYSIS_ROOTS);
// request.setParameter(INCLUDED, ['/project']);
// request.setParameter(EXCLUDED, []);
// handleSuccessfulRequest(request);
// }
String addFile(String path, String content) {
resourceProvider.newFile(path, content);
return path;
}
String addTestFile(String content) {
addFile(testFile, content);
this.testCode = content;
return testFile;
}
/**
* Validates that the given [request] is handled successfully.
*/
void handleSuccessfulRequest(Request request) {
Response response = handler.handleRequest(request);
expect(response, isResponseSuccess('0'));
}
static String _getCodeString(code) {
if (code is List<String>) {
code = code.join('\n');
}
return code as String;
}
}
class AnalysisError {
final String file;
final String errorCode;
final int offset;
final int length;
final String message;
final String correction;
AnalysisError(this.file, this.errorCode, this.offset, this.length,
this.message, this.correction);
@override
String toString() {
return 'NotificationError(file=$file; errorCode=$errorCode; '
'offset=$offset; length=$length; message=$message)';
}
}
AnalysisError _jsonToAnalysisError(Map<String, Object> json) {
return new AnalysisError(
json['file'],
json['errorCode'],
json['offset'],
json['length'],
json['message'],
json['correction']);
}
int findIdentifierLength(String search) {
int length = 0;
while (length < search.length) {
int 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;
}