mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Convert more doc comments in analysis_server
Change-Id: I333d0af4444226a8152e840c4d9015fb4c30bd32 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/135700 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
4ca3d267ee
commit
b03ef5b3fe
|
@ -24,9 +24,7 @@ import 'package:meta/meta.dart';
|
|||
|
||||
import 'src/utilities/mock_packages.dart';
|
||||
|
||||
/**
|
||||
* Finds an [Element] with the given [name].
|
||||
*/
|
||||
/// Finds an [Element] with the given [name].
|
||||
Element findChildElement(Element root, String name, [ElementKind kind]) {
|
||||
Element result;
|
||||
root.accept(_ElementVisitorFunctionWrapper((Element element) {
|
||||
|
@ -41,9 +39,7 @@ Element findChildElement(Element root, String name, [ElementKind kind]) {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function to be called for every [Element].
|
||||
*/
|
||||
/// A function to be called for every [Element].
|
||||
typedef _ElementVisitorFunction = void Function(Element element);
|
||||
|
||||
class AbstractContextTest with ResourceProviderMixin {
|
||||
|
@ -213,10 +209,8 @@ test:${toUriStr('/home/test/lib')}
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the given [_ElementVisitorFunction] into an instance of
|
||||
* [engine.GeneralizingElementVisitor].
|
||||
*/
|
||||
/// Wraps the given [_ElementVisitorFunction] into an instance of
|
||||
/// [engine.GeneralizingElementVisitor].
|
||||
class _ElementVisitorFunctionWrapper extends GeneralizingElementVisitor<void> {
|
||||
final _ElementVisitorFunction function;
|
||||
_ElementVisitorFunctionWrapper(this.function);
|
||||
|
|
|
@ -44,9 +44,7 @@ class AbstractSingleUnitTest extends AbstractContextTest {
|
|||
return findOffset(search) + search.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the [SimpleIdentifier] at the given search pattern.
|
||||
*/
|
||||
/// Returns the [SimpleIdentifier] at the given search pattern.
|
||||
SimpleIdentifier findIdentifier(String search) {
|
||||
return findNodeAtString(search, (node) => node is SimpleIdentifier);
|
||||
}
|
||||
|
|
|
@ -24,12 +24,10 @@ class AnalysisNotificationImplementedTest extends AbstractAnalysisTest {
|
|||
List<ImplementedClass> implementedClasses;
|
||||
List<ImplementedMember> implementedMembers;
|
||||
|
||||
/**
|
||||
* Validates that there is an [ImplementedClass] at the offset of [search].
|
||||
*
|
||||
* If [length] is not specified explicitly, then length of an identifier
|
||||
* from [search] is used.
|
||||
*/
|
||||
/// Validates that there is an [ImplementedClass] at the offset of [search].
|
||||
///
|
||||
/// If [length] is not specified explicitly, then length of an identifier
|
||||
/// from [search] is used.
|
||||
void assertHasImplementedClass(String search, [int length = -1]) {
|
||||
int offset = findOffset(search);
|
||||
if (length == -1) {
|
||||
|
@ -47,12 +45,10 @@ class AnalysisNotificationImplementedTest extends AbstractAnalysisTest {
|
|||
' in $implementedClasses');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is an [ImplementedClass] at the offset of [search].
|
||||
*
|
||||
* If [length] is not specified explicitly, then length of an identifier
|
||||
* from [search] is used.
|
||||
*/
|
||||
/// Validates that there is an [ImplementedClass] at the offset of [search].
|
||||
///
|
||||
/// If [length] is not specified explicitly, then length of an identifier
|
||||
/// from [search] is used.
|
||||
void assertHasImplementedMember(String search, [int length = -1]) {
|
||||
int offset = findOffset(search);
|
||||
if (length == -1) {
|
||||
|
@ -70,12 +66,10 @@ class AnalysisNotificationImplementedTest extends AbstractAnalysisTest {
|
|||
' in $implementedMembers');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is no [ImplementedMember] at the offset of [search].
|
||||
*
|
||||
* If [length] is not specified explicitly, then length of an identifier
|
||||
* from [search] is used.
|
||||
*/
|
||||
/// Validates that there is no [ImplementedMember] at the offset of [search].
|
||||
///
|
||||
/// If [length] is not specified explicitly, then length of an identifier
|
||||
/// from [search] is used.
|
||||
void assertNoImplementedMember(String search, [int length = -1]) {
|
||||
int offset = findOffset(search);
|
||||
if (length == -1) {
|
||||
|
@ -92,9 +86,7 @@ class AnalysisNotificationImplementedTest extends AbstractAnalysisTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe for `IMPLEMENTED` and wait for the notification.
|
||||
*/
|
||||
/// Subscribe for `IMPLEMENTED` and wait for the notification.
|
||||
Future prepareImplementedElements() {
|
||||
subscribeForImplemented();
|
||||
return waitForImplementedElements();
|
||||
|
|
|
@ -29,10 +29,8 @@ class AbstractNavigationTest extends AbstractAnalysisTest {
|
|||
List<NavigationTarget> testTargets;
|
||||
NavigationTarget testTarget;
|
||||
|
||||
/**
|
||||
* Validates that there is a target in [testTargetIndexes] with [file],
|
||||
* at [offset] and with the given [length].
|
||||
*/
|
||||
/// Validates that there is a target in [testTargetIndexes] with [file],
|
||||
/// at [offset] and with the given [length].
|
||||
void assertHasFileTarget(String file, int offset, int length) {
|
||||
for (NavigationTarget target in testTargets) {
|
||||
if (targetFiles[target.fileIndex] == file &&
|
||||
|
@ -54,11 +52,9 @@ class AbstractNavigationTest extends AbstractAnalysisTest {
|
|||
assertHasTarget(targetSearch, targetLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is a region at the offset of [search] in [testFile].
|
||||
* If [length] is not specified explicitly, then length of an identifier
|
||||
* from [search] is used.
|
||||
*/
|
||||
/// Validates that there is a region at the offset of [search] in [testFile].
|
||||
/// If [length] is not specified explicitly, then length of an identifier
|
||||
/// from [search] is used.
|
||||
void assertHasRegion(String search, [int length = -1]) {
|
||||
int offset = findOffset(search);
|
||||
if (length == -1) {
|
||||
|
@ -67,10 +63,8 @@ class AbstractNavigationTest extends AbstractAnalysisTest {
|
|||
findRegion(offset, length, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is a region at the offset of [search] in [testFile]
|
||||
* with the given [length] or the length of [search].
|
||||
*/
|
||||
/// Validates that there is a region at the offset of [search] in [testFile]
|
||||
/// with the given [length] or the length of [search].
|
||||
void assertHasRegionString(String search, [int length = -1]) {
|
||||
int offset = findOffset(search);
|
||||
if (length == -1) {
|
||||
|
@ -79,20 +73,16 @@ class AbstractNavigationTest extends AbstractAnalysisTest {
|
|||
findRegion(offset, length, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is an identifier region at [regionSearch] with target
|
||||
* at [targetSearch].
|
||||
*/
|
||||
/// Validates that there is an identifier region at [regionSearch] with target
|
||||
/// at [targetSearch].
|
||||
void assertHasRegionTarget(String regionSearch, String targetSearch) {
|
||||
assertHasRegion(regionSearch);
|
||||
assertHasTarget(targetSearch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is a target in [testTargets] with [testFile], at the
|
||||
* offset of [search] in [testFile], and with the given [length] or the length
|
||||
* of an leading identifier in [search].
|
||||
*/
|
||||
/// Validates that there is a target in [testTargets] with [testFile], at the
|
||||
/// offset of [search] in [testFile], and with the given [length] or the
|
||||
/// length of an leading identifier in [search].
|
||||
void assertHasTarget(String search, [int length = -1]) {
|
||||
int offset = findOffset(search);
|
||||
if (length == -1) {
|
||||
|
@ -101,34 +91,26 @@ class AbstractNavigationTest extends AbstractAnalysisTest {
|
|||
assertHasFileTarget(testFile, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is a target in [testTargets] with [testFile], at the
|
||||
* offset of [str] in [testFile], and with the length of [str].
|
||||
*/
|
||||
/// Validates that there is a target in [testTargets] with [testFile], at the
|
||||
/// offset of [str] in [testFile], and with the length of [str].
|
||||
void assertHasTargetString(String str) {
|
||||
assertHasTarget(str, str.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is no a region at [search] and with the given
|
||||
* [length].
|
||||
*/
|
||||
/// Validates that there is no a region at [search] and with the given
|
||||
/// [length].
|
||||
void assertNoRegion(String search, int length) {
|
||||
int offset = findOffset(search);
|
||||
findRegion(offset, length, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is no a region at [search] with any length.
|
||||
*/
|
||||
/// Validates that there is no a region at [search] with any length.
|
||||
void assertNoRegionAt(String search) {
|
||||
int offset = findOffset(search);
|
||||
findRegion(offset, -1, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is no a region for [search] string.
|
||||
*/
|
||||
/// Validates that there is no a region for [search] string.
|
||||
void assertNoRegionString(String search) {
|
||||
int offset = findOffset(search);
|
||||
int length = search.length;
|
||||
|
@ -146,16 +128,14 @@ class AbstractNavigationTest extends AbstractAnalysisTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the navigation region with the given [offset] and [length].
|
||||
* If [length] is `-1`, then it is ignored.
|
||||
*
|
||||
* If [exists] is `true`, then fails if such region does not exist.
|
||||
* Otherwise remembers this it into [testRegion].
|
||||
* Also fills [testTargets] with its targets.
|
||||
*
|
||||
* If [exists] is `false`, then fails if such region exists.
|
||||
*/
|
||||
/// Finds the navigation region with the given [offset] and [length].
|
||||
/// If [length] is `-1`, then it is ignored.
|
||||
///
|
||||
/// If [exists] is `true`, then fails if such region does not exist.
|
||||
/// Otherwise remembers this it into [testRegion].
|
||||
/// Also fills [testTargets] with its targets.
|
||||
///
|
||||
/// If [exists] is `false`, then fails if such region exists.
|
||||
void findRegion(int offset, int length, bool exists) {
|
||||
for (NavigationRegion region in regions) {
|
||||
if (region.offset == offset &&
|
||||
|
|
|
@ -26,19 +26,15 @@ class AnalysisNotificationOccurrencesTest extends AbstractAnalysisTest {
|
|||
|
||||
final Completer<void> _resultsAvailable = Completer();
|
||||
|
||||
/**
|
||||
* Asserts that there is an offset of [search] in [testOccurrences].
|
||||
*/
|
||||
/// Asserts that there is an offset of [search] in [testOccurrences].
|
||||
void assertHasOffset(String search) {
|
||||
int offset = findOffset(search);
|
||||
expect(testOccurrences.offsets, contains(offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is a region at the offset of [search] in [testFile].
|
||||
* If [length] is not specified explicitly, then length of an identifier
|
||||
* from [search] is used.
|
||||
*/
|
||||
/// Validates that there is a region at the offset of [search] in [testFile].
|
||||
/// If [length] is not specified explicitly, then length of an identifier
|
||||
/// from [search] is used.
|
||||
void assertHasRegion(String search, [int length = -1]) {
|
||||
int offset = findOffset(search);
|
||||
if (length == -1) {
|
||||
|
@ -47,14 +43,12 @@ class AnalysisNotificationOccurrencesTest extends AbstractAnalysisTest {
|
|||
findRegion(offset, length, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an [Occurrences] with the given [offset] and [length].
|
||||
*
|
||||
* If [exists] is `true`, then fails if such [Occurrences] does not exist.
|
||||
* Otherwise remembers this it into [testOccurrences].
|
||||
*
|
||||
* If [exists] is `false`, then fails if such [Occurrences] exists.
|
||||
*/
|
||||
/// Finds an [Occurrences] with the given [offset] and [length].
|
||||
///
|
||||
/// If [exists] is `true`, then fails if such [Occurrences] does not exist.
|
||||
/// Otherwise remembers this it into [testOccurrences].
|
||||
///
|
||||
/// If [exists] is `false`, then fails if such [Occurrences] exists.
|
||||
void findRegion(int offset, int length, [bool exists]) {
|
||||
for (Occurrences occurrences in occurrencesList) {
|
||||
if (occurrences.length != length) {
|
||||
|
|
|
@ -25,10 +25,8 @@ class AnalysisNotificationOverridesTest extends AbstractAnalysisTest {
|
|||
|
||||
final Completer<void> _resultsAvailable = Completer();
|
||||
|
||||
/**
|
||||
* Asserts that there is an overridden interface [OverriddenMember] at the
|
||||
* offset of [search] in [override].
|
||||
*/
|
||||
/// Asserts that there is an overridden interface [OverriddenMember] at the
|
||||
/// offset of [search] in [override].
|
||||
void assertHasInterfaceMember(String search) {
|
||||
int offset = findOffset(search);
|
||||
for (OverriddenMember member in overrideObject.interfaceMembers) {
|
||||
|
@ -40,12 +38,10 @@ class AnalysisNotificationOverridesTest extends AbstractAnalysisTest {
|
|||
'${overrideObject.interfaceMembers.join('\n')}');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is an [Override] at the offset of [search].
|
||||
*
|
||||
* If [length] is not specified explicitly, then length of an identifier
|
||||
* from [search] is used.
|
||||
*/
|
||||
/// Validates that there is an [Override] at the offset of [search].
|
||||
///
|
||||
/// If [length] is not specified explicitly, then length of an identifier
|
||||
/// from [search] is used.
|
||||
void assertHasOverride(String search, [int length = -1]) {
|
||||
int offset = findOffset(search);
|
||||
if (length == -1) {
|
||||
|
@ -54,29 +50,23 @@ class AnalysisNotificationOverridesTest extends AbstractAnalysisTest {
|
|||
findOverride(offset, length, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that there is an overridden superclass [OverriddenMember] at the
|
||||
* offset of [search] in [override].
|
||||
*/
|
||||
/// Asserts that there is an overridden superclass [OverriddenMember] at the
|
||||
/// offset of [search] in [override].
|
||||
void assertHasSuperElement(String search) {
|
||||
int offset = findOffset(search);
|
||||
OverriddenMember member = overrideObject.superclassMember;
|
||||
expect(member.element.location.offset, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that there are no overridden members from interfaces.
|
||||
*/
|
||||
/// Asserts that there are no overridden members from interfaces.
|
||||
void assertNoInterfaceMembers() {
|
||||
expect(overrideObject.interfaceMembers, isNull);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that there is no [Override] at the offset of [search].
|
||||
*
|
||||
* If [length] is not specified explicitly, then length of an identifier
|
||||
* from [search] is used.
|
||||
*/
|
||||
/// Validates that there is no [Override] at the offset of [search].
|
||||
///
|
||||
/// If [length] is not specified explicitly, then length of an identifier
|
||||
/// from [search] is used.
|
||||
void assertNoOverride(String search, [int length = -1]) {
|
||||
int offset = findOffset(search);
|
||||
if (length == -1) {
|
||||
|
@ -85,21 +75,17 @@ class AnalysisNotificationOverridesTest extends AbstractAnalysisTest {
|
|||
findOverride(offset, length, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that there are no overridden member from the superclass.
|
||||
*/
|
||||
/// Asserts that there are no overridden member from the superclass.
|
||||
void assertNoSuperMember() {
|
||||
expect(overrideObject.superclassMember, isNull);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an [Override] with the given [offset] and [length].
|
||||
*
|
||||
* If [exists] is `true`, then fails if such [Override] does not exist.
|
||||
* Otherwise remembers this it into [override].
|
||||
*
|
||||
* If [exists] is `false`, then fails if such [Override] exists.
|
||||
*/
|
||||
/// Finds an [Override] with the given [offset] and [length].
|
||||
///
|
||||
/// If [exists] is `true`, then fails if such [Override] does not exist.
|
||||
/// Otherwise remembers this it into [override].
|
||||
///
|
||||
/// If [exists] is `false`, then fails if such [Override] exists.
|
||||
void findOverride(int offset, int length, [bool exists]) {
|
||||
for (Override override in overridesList) {
|
||||
if (override.offset == offset && override.length == length) {
|
||||
|
|
|
@ -37,9 +37,7 @@ int findIdentifierLength(String search) {
|
|||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract base for all 'analysis' domain tests.
|
||||
*/
|
||||
/// An abstract base for all 'analysis' domain tests.
|
||||
class AbstractAnalysisTest with ResourceProviderMixin {
|
||||
bool generateSummaryFiles = false;
|
||||
MockServerChannel serverChannel;
|
||||
|
@ -130,9 +128,7 @@ class AbstractAnalysisTest with ResourceProviderMixin {
|
|||
InstrumentationService.NULL_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a project [projectPath].
|
||||
*/
|
||||
/// Creates a project [projectPath].
|
||||
void createProject({Map<String, String> packageRoots}) {
|
||||
newFolder(projectPath);
|
||||
Request request = AnalysisSetAnalysisRootsParams([projectPath], [],
|
||||
|
@ -147,10 +143,8 @@ class AbstractAnalysisTest with ResourceProviderMixin {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset of [search] in the file at the given [path].
|
||||
* Fails if not found.
|
||||
*/
|
||||
/// Returns the offset of [search] in the file at the given [path].
|
||||
/// Fails if not found.
|
||||
int findFileOffset(String path, String search) {
|
||||
File file = getFile(path);
|
||||
String code = file.createSource().contents.data;
|
||||
|
@ -159,19 +153,15 @@ class AbstractAnalysisTest with ResourceProviderMixin {
|
|||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset of [search] in [testCode].
|
||||
* Fails if not found.
|
||||
*/
|
||||
/// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the given [request] is handled successfully.
|
||||
*/
|
||||
/// Validates that the given [request] is handled successfully.
|
||||
Response handleSuccessfulRequest(Request request, {RequestHandler handler}) {
|
||||
handler ??= this.handler;
|
||||
Response response = handler.handleRequest(request);
|
||||
|
@ -227,17 +217,13 @@ class AbstractAnalysisTest with ResourceProviderMixin {
|
|||
serverChannel = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [Future] that completes when the server's analysis is complete.
|
||||
*/
|
||||
/// Returns a [Future] that completes when the server's analysis is complete.
|
||||
Future waitForTasksFinished() {
|
||||
return server.onAnalysisComplete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes with a successful [Response] for the given [request].
|
||||
* Otherwise fails.
|
||||
*/
|
||||
/// Completes with a successful [Response] for the given [request].
|
||||
/// Otherwise fails.
|
||||
Future<Response> waitResponse(Request request,
|
||||
{bool throwOnError = true}) async {
|
||||
return serverChannel.sendRequest(request, throwOnError: throwOnError);
|
||||
|
|
|
@ -30,10 +30,8 @@ class AnalysisServerTest with ResourceProviderMixin {
|
|||
MockServerChannel channel;
|
||||
AnalysisServer server;
|
||||
|
||||
/**
|
||||
* Test that having multiple analysis contexts analyze the same file doesn't
|
||||
* cause that file to receive duplicate notifications when it's modified.
|
||||
*/
|
||||
/// Test that having multiple analysis contexts analyze the same file doesn't
|
||||
/// cause that file to receive duplicate notifications when it's modified.
|
||||
Future do_not_test_no_duplicate_notifications() async {
|
||||
// Subscribe to STATUS so we'll know when analysis is done.
|
||||
server.serverServices = {ServerService.STATUS};
|
||||
|
|
|
@ -23,20 +23,14 @@ void main() {
|
|||
class ByteStreamClientChannelTest {
|
||||
ByteStreamClientChannel channel;
|
||||
|
||||
/**
|
||||
* Sink that may be used to deliver data to the channel, as though it's
|
||||
* coming from the server.
|
||||
*/
|
||||
/// Sink that may be used to deliver data to the channel, as though it's
|
||||
/// coming from the server.
|
||||
IOSink inputSink;
|
||||
|
||||
/**
|
||||
* Sink through which the channel delivers data to the server.
|
||||
*/
|
||||
/// Sink through which the channel delivers data to the server.
|
||||
IOSink outputSink;
|
||||
|
||||
/**
|
||||
* Stream of lines sent back to the client by the channel.
|
||||
*/
|
||||
/// Stream of lines sent back to the client by the channel.
|
||||
Stream<String> outputLineStream;
|
||||
|
||||
void setUp() {
|
||||
|
@ -109,30 +103,20 @@ class ByteStreamClientChannelTest {
|
|||
class ByteStreamServerChannelTest {
|
||||
ByteStreamServerChannel channel;
|
||||
|
||||
/**
|
||||
* Sink that may be used to deliver data to the channel, as though it's
|
||||
* coming from the client.
|
||||
*/
|
||||
/// Sink that may be used to deliver data to the channel, as though it's
|
||||
/// coming from the client.
|
||||
IOSink inputSink;
|
||||
|
||||
/**
|
||||
* Stream of lines sent back to the client by the channel.
|
||||
*/
|
||||
/// Stream of lines sent back to the client by the channel.
|
||||
Stream<String> outputLineStream;
|
||||
|
||||
/**
|
||||
* Stream of requests received from the channel via [listen()].
|
||||
*/
|
||||
/// Stream of requests received from the channel via [listen()].
|
||||
Stream<Request> requestStream;
|
||||
|
||||
/**
|
||||
* Stream of errors received from the channel via [listen()].
|
||||
*/
|
||||
/// Stream of errors received from the channel via [listen()].
|
||||
Stream errorStream;
|
||||
|
||||
/**
|
||||
* Future which is completed when then [listen()] reports [onDone].
|
||||
*/
|
||||
/// Future which is completed when then [listen()] reports [onDone].
|
||||
Future doneFuture;
|
||||
|
||||
void setUp() {
|
||||
|
|
|
@ -14,18 +14,12 @@ void main() {
|
|||
builder.buildAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder that builds the completion tests.
|
||||
*/
|
||||
/// A builder that builds the completion tests.
|
||||
class CompletionTestBuilder {
|
||||
/**
|
||||
* Number of tests that have been built that are expected to pass.
|
||||
*/
|
||||
/// Number of tests that have been built that are expected to pass.
|
||||
int expectedPassCount = 0;
|
||||
|
||||
/**
|
||||
* Number of tests that have been built that are expected to fail.
|
||||
*/
|
||||
/// Number of tests that have been built that are expected to fail.
|
||||
int expectedFailCount = 0;
|
||||
|
||||
void buildAll() {
|
||||
|
@ -2401,26 +2395,24 @@ class A<Z extends X> {
|
|||
<String>['2+B']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a set of completion tests based on the given [originalSource].
|
||||
*
|
||||
* The source string has completion points embedded in it, which are
|
||||
* identified by '!X' where X is a single character. Each X is matched to
|
||||
* positive or negative results in the array of [validationStrings].
|
||||
* Validation strings contain the name of a prediction with a two character
|
||||
* prefix. The first character of the prefix corresponds to an X in the
|
||||
* [originalSource]. The second character is either a '+' or a '-' indicating
|
||||
* whether the string is a positive or negative result.
|
||||
*
|
||||
* The [originalSource] is the source for a completion test that contains
|
||||
* completion points. The [validationStrings] are the positive and negative
|
||||
* predictions.
|
||||
*
|
||||
* Optional argument [failingTests], if given, is a string, each character of
|
||||
* which corresponds to an X in the [originalSource] for which the test is
|
||||
* expected to fail. This should be used to mark known completion bugs that
|
||||
* have not yet been fixed.
|
||||
*/
|
||||
/// Generate a set of completion tests based on the given [originalSource].
|
||||
///
|
||||
/// The source string has completion points embedded in it, which are
|
||||
/// identified by '!X' where X is a single character. Each X is matched to
|
||||
/// positive or negative results in the array of [validationStrings].
|
||||
/// Validation strings contain the name of a prediction with a two character
|
||||
/// prefix. The first character of the prefix corresponds to an X in the
|
||||
/// [originalSource]. The second character is either a '+' or a '-' indicating
|
||||
/// whether the string is a positive or negative result.
|
||||
///
|
||||
/// The [originalSource] is the source for a completion test that contains
|
||||
/// completion points. The [validationStrings] are the positive and negative
|
||||
/// predictions.
|
||||
///
|
||||
/// Optional argument [failingTests], if given, is a string, each character of
|
||||
/// which corresponds to an X in the [originalSource] for which the test is
|
||||
/// expected to fail. This should be used to mark known completion bugs that
|
||||
/// have not yet been fixed.
|
||||
void buildTests(String baseName, String originalSource, List<String> results,
|
||||
{Map<String, String> extraFiles, String failingTests = ''}) {
|
||||
List<LocationSpec> completionTests =
|
||||
|
|
|
@ -10,9 +10,7 @@ import 'package:test/test.dart';
|
|||
|
||||
import 'domain_completion_test.dart';
|
||||
|
||||
/**
|
||||
* A base class for classes containing completion tests.
|
||||
*/
|
||||
/// A base class for classes containing completion tests.
|
||||
class CompletionTestCase extends CompletionDomainHandlerListTokenDetailsTest {
|
||||
static const String CURSOR_MARKER = '!';
|
||||
|
||||
|
@ -64,10 +62,8 @@ class CompletionTestCase extends CompletionDomainHandlerListTokenDetailsTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discard any results that do not start with the characters the user has
|
||||
* "already typed".
|
||||
*/
|
||||
/// Discard any results that do not start with the characters the user has
|
||||
/// "already typed".
|
||||
void filterResults(String content) {
|
||||
String charsAlreadyTyped =
|
||||
content.substring(replacementOffset, completionOffset).toLowerCase();
|
||||
|
@ -103,9 +99,7 @@ class CompletionTestCase extends CompletionDomainHandlerListTokenDetailsTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A specification of the completion results expected at a given location.
|
||||
*/
|
||||
/// A specification of the completion results expected at a given location.
|
||||
class LocationSpec {
|
||||
String id;
|
||||
int testLocation = -1;
|
||||
|
@ -115,22 +109,21 @@ class LocationSpec {
|
|||
|
||||
LocationSpec(this.id);
|
||||
|
||||
/**
|
||||
* Parse a set of tests from the given `originalSource`. Return a list of the
|
||||
* specifications that were parsed.
|
||||
*
|
||||
* The source string has test locations embedded in it, which are identified
|
||||
* by '!X' where X is a single character. Each X is matched to positive or
|
||||
* negative results in the array of [validationStrings]. Validation strings
|
||||
* contain the name of a prediction with a two character prefix. The first
|
||||
* character of the prefix corresponds to an X in the [originalSource]. The
|
||||
* second character is either a '+' or a '-' indicating whether the string is
|
||||
* a positive or negative result. If logical not is needed in the source it
|
||||
* can be represented by '!!'.
|
||||
*
|
||||
* The [originalSource] is the source for a test that contains test locations.
|
||||
* The [validationStrings] are the positive and negative predictions.
|
||||
*/
|
||||
/// Parse a set of tests from the given `originalSource`. Return a list of the
|
||||
/// specifications that were parsed.
|
||||
///
|
||||
/// The source string has test locations embedded in it, which are identified
|
||||
/// by '!X' where X is a single character. Each X is matched to positive or
|
||||
/// negative results in the array of [validationStrings]. Validation strings
|
||||
/// contain the name of a prediction with a two character prefix. The first
|
||||
/// character of the prefix corresponds to an X in the [originalSource]. The
|
||||
/// second character is either a '+' or a '-' indicating whether the string is
|
||||
/// a positive or negative result. If logical not is needed in the source it
|
||||
/// can be represented by '!!'.
|
||||
///
|
||||
/// The [originalSource] is the source for a test that contains test
|
||||
/// locations. The [validationStrings] are the positive and negative
|
||||
/// predictions.
|
||||
static List<LocationSpec> from(
|
||||
String originalSource, List<String> validationStrings) {
|
||||
Map<String, LocationSpec> tests = HashMap<String, LocationSpec>();
|
||||
|
|
|
@ -1601,10 +1601,8 @@ sky_engine:lib/''');
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that package URI's for source files in [path] will be resolved
|
||||
* using a package root matching [expectation].
|
||||
*/
|
||||
/// Verify that package URI's for source files in [path] will be resolved
|
||||
/// using a package root matching [expectation].
|
||||
void _checkPackageRoot(String path, expectation) {
|
||||
// TODO(brianwilkerson) Figure out how to test this. Possibly by comparing
|
||||
// the contents of the package map (although that approach doesn't work at
|
||||
|
@ -1617,29 +1615,19 @@ sky_engine:lib/''');
|
|||
}
|
||||
|
||||
abstract class ContextManagerTest with ResourceProviderMixin {
|
||||
/**
|
||||
* The name of the 'bin' directory.
|
||||
*/
|
||||
/// The name of the 'bin' directory.
|
||||
static const String BIN_NAME = 'bin';
|
||||
|
||||
/**
|
||||
* The name of the 'example' directory.
|
||||
*/
|
||||
/// The name of the 'example' directory.
|
||||
static const String EXAMPLE_NAME = 'example';
|
||||
|
||||
/**
|
||||
* The name of the 'lib' directory.
|
||||
*/
|
||||
/// The name of the 'lib' directory.
|
||||
static const String LIB_NAME = 'lib';
|
||||
|
||||
/**
|
||||
* The name of the 'src' directory.
|
||||
*/
|
||||
/// The name of the 'src' directory.
|
||||
static const String SRC_NAME = 'src';
|
||||
|
||||
/**
|
||||
* The name of the 'test' directory.
|
||||
*/
|
||||
/// The name of the 'test' directory.
|
||||
static const String TEST_NAME = 'test';
|
||||
|
||||
ContextManagerImpl manager;
|
||||
|
@ -1687,10 +1675,8 @@ abstract class ContextManagerTest with ResourceProviderMixin {
|
|||
|
||||
Map<String, List<Folder>> get _currentPackageMap => _packageMap(projPath);
|
||||
|
||||
/**
|
||||
* TODO(brianwilkerson) This doesn't add the strong mode processor when using
|
||||
* the new analysis driver.
|
||||
*/
|
||||
/// TODO(brianwilkerson) This doesn't add the strong mode processor when using
|
||||
/// the new analysis driver.
|
||||
ErrorProcessor getProcessor(AnalysisError error) => errorProcessors
|
||||
.firstWhere((ErrorProcessor p) => p.appliesTo(error), orElse: () => null);
|
||||
|
||||
|
@ -2353,67 +2339,43 @@ analyzer:
|
|||
}
|
||||
|
||||
class TestContextManagerCallbacks extends ContextManagerCallbacks {
|
||||
/**
|
||||
* Source of timestamps stored in [currentContextFilePaths].
|
||||
*/
|
||||
/// Source of timestamps stored in [currentContextFilePaths].
|
||||
int now = 0;
|
||||
|
||||
/**
|
||||
* The analysis driver that was created.
|
||||
*/
|
||||
/// The analysis driver that was created.
|
||||
AnalysisDriver currentDriver;
|
||||
|
||||
/**
|
||||
* A table mapping paths to the analysis driver associated with that path.
|
||||
*/
|
||||
/// A table mapping paths to the analysis driver associated with that path.
|
||||
Map<String, AnalysisDriver> driverMap = <String, AnalysisDriver>{};
|
||||
|
||||
/**
|
||||
* Map from context to the timestamp when the context was created.
|
||||
*/
|
||||
/// Map from context to the timestamp when the context was created.
|
||||
Map<String, int> currentContextTimestamps = <String, int>{};
|
||||
|
||||
/**
|
||||
* Map from context to (map from file path to timestamp of last event).
|
||||
*/
|
||||
/// Map from context to (map from file path to timestamp of last event).
|
||||
final Map<String, Map<String, int>> currentContextFilePaths =
|
||||
<String, Map<String, int>>{};
|
||||
|
||||
/**
|
||||
* A map from the paths of contexts to a set of the sources that should be
|
||||
* explicitly analyzed in those contexts.
|
||||
*/
|
||||
/// A map from the paths of contexts to a set of the sources that should be
|
||||
/// explicitly analyzed in those contexts.
|
||||
final Map<String, Set<Source>> currentContextSources =
|
||||
<String, Set<Source>>{};
|
||||
|
||||
/**
|
||||
* Resource provider used for this test.
|
||||
*/
|
||||
/// Resource provider used for this test.
|
||||
final ResourceProvider resourceProvider;
|
||||
|
||||
/**
|
||||
* The manager managing the SDKs.
|
||||
*/
|
||||
/// The manager managing the SDKs.
|
||||
final DartSdkManager sdkManager;
|
||||
|
||||
/**
|
||||
* The logger used by the scheduler and the driver.
|
||||
*/
|
||||
/// The logger used by the scheduler and the driver.
|
||||
final PerformanceLog logger;
|
||||
|
||||
/**
|
||||
* The scheduler used by the driver.
|
||||
*/
|
||||
/// The scheduler used by the driver.
|
||||
final AnalysisDriverScheduler scheduler;
|
||||
|
||||
/**
|
||||
* The list of `flushedFiles` in the last [removeContext] invocation.
|
||||
*/
|
||||
/// The list of `flushedFiles` in the last [removeContext] invocation.
|
||||
List<String> lastFlushedFiles;
|
||||
|
||||
/**
|
||||
* The watch events that have been broadcast.
|
||||
*/
|
||||
/// The watch events that have been broadcast.
|
||||
List<WatchEvent> watchEvents = <WatchEvent>[];
|
||||
|
||||
@override
|
||||
|
@ -2422,21 +2384,15 @@ class TestContextManagerCallbacks extends ContextManagerCallbacks {
|
|||
TestContextManagerCallbacks(
|
||||
this.resourceProvider, this.sdkManager, this.logger, this.scheduler);
|
||||
|
||||
/**
|
||||
* Return the current set of analysis options.
|
||||
*/
|
||||
/// Return the current set of analysis options.
|
||||
AnalysisOptions get analysisOptions => currentDriver?.analysisOptions;
|
||||
|
||||
/**
|
||||
* Return the paths to the context roots that currently exist.
|
||||
*/
|
||||
/// Return the paths to the context roots that currently exist.
|
||||
Iterable<String> get currentContextRoots {
|
||||
return currentContextTimestamps.keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the paths to the files being analyzed in the current context root.
|
||||
*/
|
||||
/// Return the paths to the files being analyzed in the current context root.
|
||||
Iterable<String> get currentFilePaths {
|
||||
if (currentDriver == null) {
|
||||
return <String>[];
|
||||
|
@ -2444,9 +2400,7 @@ class TestContextManagerCallbacks extends ContextManagerCallbacks {
|
|||
return currentDriver.addedFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current source factory.
|
||||
*/
|
||||
/// Return the current source factory.
|
||||
SourceFactory get sourceFactory => currentDriver?.sourceFactory;
|
||||
|
||||
@override
|
||||
|
@ -2525,9 +2479,7 @@ class TestContextManagerCallbacks extends ContextManagerCallbacks {
|
|||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the paths to the files being analyzed in the current context root.
|
||||
*/
|
||||
/// Return the paths to the files being analyzed in the current context root.
|
||||
Iterable<Source> currentFileSources(String contextPath) {
|
||||
if (currentDriver == null) {
|
||||
return <Source>[];
|
||||
|
@ -2542,9 +2494,7 @@ class TestContextManagerCallbacks extends ContextManagerCallbacks {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the paths to the files being analyzed in the current context root.
|
||||
*/
|
||||
/// Return the paths to the files being analyzed in the current context root.
|
||||
Iterable<String> getCurrentFilePaths(String contextPath) {
|
||||
if (currentDriver == null) {
|
||||
return <String>[];
|
||||
|
|
|
@ -337,9 +337,7 @@ main(A a) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to test 'analysis.*' requests.
|
||||
*/
|
||||
/// A helper to test 'analysis.*' requests.
|
||||
class AnalysisTestHelper with ResourceProviderMixin {
|
||||
MockServerChannel serverChannel;
|
||||
AnalysisServer server;
|
||||
|
@ -387,9 +385,7 @@ class AnalysisTestHelper with ResourceProviderMixin {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [Future] that completes when the server's analysis is complete.
|
||||
*/
|
||||
/// Returns a [Future] that completes when the server's analysis is complete.
|
||||
Future get onAnalysisComplete {
|
||||
return server.onAnalysisComplete;
|
||||
}
|
||||
|
@ -416,9 +412,7 @@ class AnalysisTestHelper with ResourceProviderMixin {
|
|||
addAnalysisSubscription(AnalysisService.NAVIGATION, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty project `/project`.
|
||||
*/
|
||||
/// Creates an empty project `/project`.
|
||||
void createEmptyProject() {
|
||||
newFolder(projectPath);
|
||||
Request request =
|
||||
|
@ -426,10 +420,8 @@ class AnalysisTestHelper with ResourceProviderMixin {
|
|||
handleSuccessfulRequest(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a project with a single Dart file `/project/bin/test.dart` with
|
||||
* the given [code].
|
||||
*/
|
||||
/// Creates a project with a single Dart file `/project/bin/test.dart` with
|
||||
/// the given [code].
|
||||
void createSingleFileProject(code) {
|
||||
testCode = _getCodeString(code);
|
||||
newFolder(projectPath);
|
||||
|
@ -439,20 +431,16 @@ class AnalysisTestHelper with ResourceProviderMixin {
|
|||
handleSuccessfulRequest(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset of [search] in [testCode].
|
||||
* Fails if not found.
|
||||
*/
|
||||
/// 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`.
|
||||
*/
|
||||
/// 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) {
|
||||
|
@ -461,10 +449,8 @@ class AnalysisTestHelper with ResourceProviderMixin {
|
|||
return <AnalysisError>[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns highlights recorded for the given [file].
|
||||
* May be empty, but not `null`.
|
||||
*/
|
||||
/// Returns highlights recorded for the given [file].
|
||||
/// May be empty, but not `null`.
|
||||
List<HighlightRegion> getHighlights(String file) {
|
||||
List<HighlightRegion> highlights = filesHighlights[file];
|
||||
if (highlights != null) {
|
||||
|
@ -473,10 +459,8 @@ class AnalysisTestHelper with ResourceProviderMixin {
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns navigation regions recorded for the given [file].
|
||||
* May be empty, but not `null`.
|
||||
*/
|
||||
/// Returns navigation regions recorded for the given [file].
|
||||
/// May be empty, but not `null`.
|
||||
List<NavigationRegion> getNavigation(String file) {
|
||||
List<NavigationRegion> navigation = filesNavigation[file];
|
||||
if (navigation != null) {
|
||||
|
@ -485,50 +469,38 @@ class AnalysisTestHelper with ResourceProviderMixin {
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns [AnalysisError]s recorded for the [testFile].
|
||||
* May be empty, but not `null`.
|
||||
*/
|
||||
/// 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`.
|
||||
*/
|
||||
/// Returns highlights recorded for the given [testFile].
|
||||
/// May be empty, but not `null`.
|
||||
List<HighlightRegion> getTestHighlights() {
|
||||
return getHighlights(testFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns navigation information recorded for the given [testFile].
|
||||
* May be empty, but not `null`.
|
||||
*/
|
||||
/// Returns navigation information recorded for the given [testFile].
|
||||
/// May be empty, but not `null`.
|
||||
List<NavigationRegion> getTestNavigation() {
|
||||
return getNavigation(testFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the given [request] is handled successfully.
|
||||
*/
|
||||
/// Validates that the given [request] is handled successfully.
|
||||
void handleSuccessfulRequest(Request request) {
|
||||
Response response = handler.handleRequest(request);
|
||||
expect(response, isResponseSuccess('0'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an `updateContent` request for [testFile].
|
||||
*/
|
||||
/// Send an `updateContent` request for [testFile].
|
||||
void sendContentChange(dynamic contentChange) {
|
||||
Request request =
|
||||
AnalysisUpdateContentParams({testFile: contentChange}).toRequest('0');
|
||||
handleSuccessfulRequest(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the associated server.
|
||||
*/
|
||||
/// Stops the associated server.
|
||||
void stopServer() {
|
||||
server.done();
|
||||
}
|
||||
|
|
|
@ -822,10 +822,8 @@ flutter:${libFolder.toUri()}
|
|||
''');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that there is refactoring of the given [kind] is available at the
|
||||
* [search] offset.
|
||||
*/
|
||||
/// Tests that there is refactoring of the given [kind] is available at the
|
||||
/// [search] offset.
|
||||
Future assertHasKind(
|
||||
String code, String search, RefactoringKind kind, bool expected) async {
|
||||
addTestFile(code);
|
||||
|
@ -839,17 +837,13 @@ flutter:${libFolder.toUri()}
|
|||
expect(kinds, matcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that there is a RENAME refactoring available at the [search] offset.
|
||||
*/
|
||||
/// Tests that there is a RENAME refactoring available at the [search] offset.
|
||||
Future assertHasRenameRefactoring(String code, String search) async {
|
||||
return assertHasKind(code, search, RefactoringKind.RENAME, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of available refactorings for the given [offset] and
|
||||
* [length].
|
||||
*/
|
||||
/// Returns the list of available refactorings for the given [offset] and
|
||||
/// [length].
|
||||
Future getRefactorings(int offset, int length) async {
|
||||
Request request =
|
||||
EditGetAvailableRefactoringsParams(testFile, offset, length)
|
||||
|
@ -860,9 +854,7 @@ flutter:${libFolder.toUri()}
|
|||
kinds = result.kinds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of available refactorings at the offset of [search].
|
||||
*/
|
||||
/// Returns the list of available refactorings at the offset of [search].
|
||||
Future getRefactoringsAtString(String search) {
|
||||
int offset = findOffset(search);
|
||||
return getRefactorings(offset, 0);
|
||||
|
@ -2132,9 +2124,7 @@ main() {
|
|||
class _AbstractGetRefactoring_Test extends AbstractAnalysisTest {
|
||||
bool shouldWaitForFullAnalysis = true;
|
||||
|
||||
/**
|
||||
* Asserts that [problems] has a single ERROR problem.
|
||||
*/
|
||||
/// Asserts that [problems] has a single ERROR problem.
|
||||
void assertResultProblemsError(List<RefactoringProblem> problems,
|
||||
[String message]) {
|
||||
RefactoringProblem problem = problems[0];
|
||||
|
@ -2145,9 +2135,7 @@ class _AbstractGetRefactoring_Test extends AbstractAnalysisTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that [result] has a single FATAL problem.
|
||||
*/
|
||||
/// Asserts that [result] has a single FATAL problem.
|
||||
void assertResultProblemsFatal(List<RefactoringProblem> problems,
|
||||
[String message]) {
|
||||
RefactoringProblem problem = problems[0];
|
||||
|
@ -2159,18 +2147,14 @@ class _AbstractGetRefactoring_Test extends AbstractAnalysisTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that [result] has no problems at all.
|
||||
*/
|
||||
/// Asserts that [result] has no problems at all.
|
||||
void assertResultProblemsOK(EditGetRefactoringResult result) {
|
||||
expect(result.initialProblems, isEmpty);
|
||||
expect(result.optionsProblems, isEmpty);
|
||||
expect(result.finalProblems, isEmpty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that [result] has a single WARNING problem.
|
||||
*/
|
||||
/// Asserts that [result] has a single WARNING problem.
|
||||
void assertResultProblemsWarning(List<RefactoringProblem> problems,
|
||||
[String message]) {
|
||||
RefactoringProblem problem = problems[0];
|
||||
|
@ -2193,10 +2177,8 @@ class _AbstractGetRefactoring_Test extends AbstractAnalysisTest {
|
|||
assertTestRefactoringResult(result, expectedCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given [EditGetRefactoringResult] has a [testFile] change
|
||||
* which results in the [expectedCode].
|
||||
*/
|
||||
/// Asserts that the given [EditGetRefactoringResult] has a [testFile] change
|
||||
/// which results in the [expectedCode].
|
||||
void assertTestRefactoringResult(
|
||||
EditGetRefactoringResult result, String expectedCode) {
|
||||
SourceChange change = result.change;
|
||||
|
|
|
@ -18,10 +18,8 @@ void main() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that when an SDK path is specified on the command-line (via the `--sdk`
|
||||
* argument) that the specified SDK is used.
|
||||
*/
|
||||
/// Tests that when an SDK path is specified on the command-line (via the
|
||||
/// `--sdk` argument) that the specified SDK is used.
|
||||
@reflectiveTest
|
||||
class AnalysisDomainGetErrorsTest
|
||||
extends AbstractAnalysisServerIntegrationTest {
|
||||
|
|
|
@ -20,14 +20,10 @@ void main() {
|
|||
@reflectiveTest
|
||||
class AnalysisGetHoverIntegrationTest
|
||||
extends AbstractAnalysisServerIntegrationTest {
|
||||
/**
|
||||
* Pathname of the file containing Dart code.
|
||||
*/
|
||||
/// Pathname of the file containing Dart code.
|
||||
String pathname;
|
||||
|
||||
/**
|
||||
* Dart code under test.
|
||||
*/
|
||||
/// Dart code under test.
|
||||
final String text = r'''
|
||||
library lib.test;
|
||||
|
||||
|
@ -48,19 +44,17 @@ main() {
|
|||
}
|
||||
''';
|
||||
|
||||
/**
|
||||
* Check that a getHover request on the substring [target] produces a result
|
||||
* which has length [length], has an elementDescription matching every
|
||||
* regexp in [descriptionRegexps], has a kind of [kind], and has a staticType
|
||||
* matching [staticTypeRegexps].
|
||||
*
|
||||
* [isCore] means the hover info should indicate that the element is defined
|
||||
* in dart.core. [docRegexp], if specified, should match the documentation
|
||||
* string of the element. [isLiteral] means the hover should indicate a
|
||||
* literal value. [parameterRegexps] means is a set of regexps which should
|
||||
* match the hover parameters. [propagatedType], if specified, is the
|
||||
* expected propagated type of the element.
|
||||
*/
|
||||
/// Check that a getHover request on the substring [target] produces a result
|
||||
/// which has length [length], has an elementDescription matching every
|
||||
/// regexp in [descriptionRegexps], has a kind of [kind], and has a staticType
|
||||
/// matching [staticTypeRegexps].
|
||||
///
|
||||
/// [isCore] means the hover info should indicate that the element is defined
|
||||
/// in dart.core. [docRegexp], if specified, should match the documentation
|
||||
/// string of the element. [isLiteral] means the hover should indicate a
|
||||
/// literal value. [parameterRegexps] means is a set of regexps which should
|
||||
/// match the hover parameters. [propagatedType], if specified, is the
|
||||
/// expected propagated type of the element.
|
||||
Future<AnalysisGetHoverResult> checkHover(
|
||||
String target,
|
||||
int length,
|
||||
|
@ -123,10 +117,8 @@ main() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a getHover request on the substring [target] produces no
|
||||
* results.
|
||||
*/
|
||||
/// Check that a getHover request on the substring [target] produces no
|
||||
/// results.
|
||||
Future checkNoHover(String target) {
|
||||
int offset = text.indexOf(target);
|
||||
return sendAnalysisGetHover(pathname, offset).then((result) {
|
||||
|
|
|
@ -21,21 +21,15 @@ void main() {
|
|||
@reflectiveTest
|
||||
class AnalysisGetImportedElementsIntegrationTest
|
||||
extends AbstractAnalysisServerIntegrationTest {
|
||||
/**
|
||||
* Pathname of the file containing Dart code.
|
||||
*/
|
||||
/// Pathname of the file containing Dart code.
|
||||
String pathname;
|
||||
|
||||
/**
|
||||
* Dart code under test.
|
||||
*/
|
||||
/// Dart code under test.
|
||||
String text;
|
||||
|
||||
/**
|
||||
* Check that an analysis.getImportedElements request on the region starting
|
||||
* with the first character that matches [target] and having the given
|
||||
* [length] matches the given list of [expected] imported elements.
|
||||
*/
|
||||
/// Check that an analysis.getImportedElements request on the region starting
|
||||
/// with the first character that matches [target] and having the given
|
||||
/// [length] matches the given list of [expected] imported elements.
|
||||
Future<void> checkElements(
|
||||
String target, List<ImportedElements> expected) async {
|
||||
bool equals(
|
||||
|
@ -81,10 +75,8 @@ class AnalysisGetImportedElementsIntegrationTest
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that an analysis.getImportedElements request on the region matching
|
||||
* [target] produces an empty list of elements.
|
||||
*/
|
||||
/// Check that an analysis.getImportedElements request on the region matching
|
||||
/// [target] produces an empty list of elements.
|
||||
Future<void> checkNoElements(String target) async {
|
||||
int offset = text.indexOf(target);
|
||||
AnalysisGetImportedElementsResult result =
|
||||
|
|
|
@ -2,12 +2,10 @@
|
|||
// 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.
|
||||
|
||||
/**
|
||||
* This test verifies that if reanalysis is performed while reanalysis is in
|
||||
* progress, no problems occur.
|
||||
*
|
||||
* See dartbug.com/21448.
|
||||
*/
|
||||
/// This test verifies that if reanalysis is performed while reanalysis is in
|
||||
/// progress, no problems occur.
|
||||
///
|
||||
/// See dartbug.com/21448.
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
|
|
|
@ -22,15 +22,11 @@ void main() {
|
|||
@reflectiveTest
|
||||
class AnalysisGetImportElementsIntegrationTest
|
||||
extends AbstractAnalysisServerIntegrationTest {
|
||||
/**
|
||||
* Pathname of the file containing Dart code.
|
||||
*/
|
||||
/// Pathname of the file containing Dart code.
|
||||
String pathname;
|
||||
|
||||
/**
|
||||
* Check that an edit.importElements request with the given list of [elements]
|
||||
* produces the [expected] list of edits.
|
||||
*/
|
||||
/// Check that an edit.importElements request with the given list of
|
||||
/// [elements] produces the [expected] list of edits.
|
||||
Future<void> checkEdits(
|
||||
List<ImportedElements> elements, List<SourceEdit> expected,
|
||||
{String expectedFile}) async {
|
||||
|
@ -71,10 +67,8 @@ class AnalysisGetImportElementsIntegrationTest
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that an edit.importElements request with the given list of [elements]
|
||||
* produces no edits.
|
||||
*/
|
||||
/// Check that an edit.importElements request with the given list of
|
||||
/// [elements] produces no edits.
|
||||
Future<void> checkNoEdits(List<ImportedElements> elements) async {
|
||||
EditImportElementsResult result =
|
||||
await sendEditImportElements(pathname, <ImportedElements>[]);
|
||||
|
|
|
@ -123,10 +123,8 @@ class LspServerClient {
|
|||
_process.kill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the root directory of the analysis_server package by proceeding
|
||||
* upward to the 'test' dir, and then going up one more directory.
|
||||
*/
|
||||
/// Find the root directory of the analysis_server package by proceeding
|
||||
/// upward to the 'test' dir, and then going up one more directory.
|
||||
String findRoot(String pathname) {
|
||||
while (!['benchmark', 'test'].contains(basename(pathname))) {
|
||||
String parent = dirname(pathname);
|
||||
|
|
|
@ -19,9 +19,7 @@ void main() {
|
|||
|
||||
@reflectiveTest
|
||||
class GetTypeHierarchyTest extends AbstractAnalysisServerIntegrationTest {
|
||||
/**
|
||||
* Pathname of the main file to run tests in.
|
||||
*/
|
||||
/// Pathname of the main file to run tests in.
|
||||
String pathname;
|
||||
|
||||
Future getTypeHierarchy_badTarget() {
|
||||
|
@ -229,30 +227,20 @@ class Pivot /* target */ extends Base2 {}
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Results of a getTypeHierarchy request, processed for easier testing.
|
||||
*/
|
||||
/// Results of a getTypeHierarchy request, processed for easier testing.
|
||||
class HierarchyResults {
|
||||
/**
|
||||
* The list of hierarchy items from the result.
|
||||
*/
|
||||
/// The list of hierarchy items from the result.
|
||||
List<TypeHierarchyItem> items;
|
||||
|
||||
/**
|
||||
* The first hierarchy item from the result, which represents the pivot
|
||||
* class.
|
||||
*/
|
||||
/// The first hierarchy item from the result, which represents the pivot
|
||||
/// class.
|
||||
TypeHierarchyItem pivot;
|
||||
|
||||
/**
|
||||
* A map from element name to item index.
|
||||
*/
|
||||
/// A map from element name to item index.
|
||||
Map<String, int> nameToIndex;
|
||||
|
||||
/**
|
||||
* Create a [HierarchyResults] object based on the result from a
|
||||
* getTypeHierarchy request.
|
||||
*/
|
||||
/// Create a [HierarchyResults] object based on the result from a
|
||||
/// getTypeHierarchy request.
|
||||
HierarchyResults(this.items) {
|
||||
pivot = items[0];
|
||||
nameToIndex = <String, int>{};
|
||||
|
@ -261,9 +249,7 @@ class HierarchyResults {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item by class name.
|
||||
*/
|
||||
/// Get an item by class name.
|
||||
TypeHierarchyItem getItem(String name) {
|
||||
if (nameToIndex.containsKey(name)) {
|
||||
return items[nameToIndex[name]];
|
||||
|
|
|
@ -38,9 +38,7 @@ Matcher isMapOf(Matcher keyMatcher, Matcher valueMatcher) =>
|
|||
|
||||
Matcher isOneOf(List<Matcher> choiceMatchers) => _OneOf(choiceMatchers);
|
||||
|
||||
/**
|
||||
* Assert that [actual] matches [matcher].
|
||||
*/
|
||||
/// Assert that [actual] matches [matcher].
|
||||
void outOfTestExpect(actual, Matcher matcher,
|
||||
{String reason, skip, bool verbose = false}) {
|
||||
var matchState = {};
|
||||
|
@ -68,80 +66,57 @@ String _defaultFailFormatter(
|
|||
return description.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of closures used by LazyMatcher.
|
||||
*/
|
||||
/// Type of closures used by LazyMatcher.
|
||||
typedef MatcherCreator = Matcher Function();
|
||||
|
||||
/**
|
||||
* Type of closures used by MatchesJsonObject to record field mismatches.
|
||||
*/
|
||||
/// Type of closures used by MatchesJsonObject to record field mismatches.
|
||||
typedef MismatchDescriber = Description Function(
|
||||
Description mismatchDescription);
|
||||
|
||||
/**
|
||||
* Type of callbacks used to process notifications.
|
||||
*/
|
||||
/// Type of callbacks used to process notifications.
|
||||
typedef NotificationProcessor = void Function(String event, Map params);
|
||||
|
||||
/**
|
||||
* Base class for analysis server integration tests.
|
||||
*/
|
||||
/// Base class for analysis server integration tests.
|
||||
abstract class AbstractAnalysisServerIntegrationTest
|
||||
extends IntegrationTestMixin {
|
||||
/**
|
||||
* Amount of time to give the server to respond to a shutdown request before
|
||||
* forcibly terminating it.
|
||||
*/
|
||||
/// Amount of time to give the server to respond to a shutdown request before
|
||||
/// forcibly terminating it.
|
||||
static const Duration SHUTDOWN_TIMEOUT = Duration(seconds: 60);
|
||||
|
||||
/**
|
||||
* Connection to the analysis server.
|
||||
*/
|
||||
/// Connection to the analysis server.
|
||||
@override
|
||||
final Server server = Server();
|
||||
|
||||
/**
|
||||
* Temporary directory in which source files can be stored.
|
||||
*/
|
||||
/// Temporary directory in which source files can be stored.
|
||||
Directory sourceDirectory;
|
||||
|
||||
/**
|
||||
* Map from file path to the list of analysis errors which have most recently
|
||||
* been received for the file.
|
||||
*/
|
||||
/// Map from file path to the list of analysis errors which have most recently
|
||||
/// been received for the file.
|
||||
Map<String, List<AnalysisError>> currentAnalysisErrors =
|
||||
HashMap<String, List<AnalysisError>>();
|
||||
|
||||
/**
|
||||
* The last list of analyzed files received.
|
||||
*/
|
||||
/// The last list of analyzed files received.
|
||||
List<String> lastAnalyzedFiles;
|
||||
|
||||
/**
|
||||
* True if the teardown process should skip sending a "server.shutdown"
|
||||
* request (e.g. because the server is known to have already shutdown).
|
||||
*/
|
||||
/// True if the teardown process should skip sending a "server.shutdown"
|
||||
/// request (e.g. because the server is known to have already shutdown).
|
||||
bool skipShutdown = false;
|
||||
|
||||
/**
|
||||
* True if we are currently subscribed to [SERVER_NOTIFICATION_STATUS] updates.
|
||||
*/
|
||||
/// True if we are currently subscribed to [SERVER_NOTIFICATION_STATUS]
|
||||
/// updates.
|
||||
bool _subscribedToServerStatus = false;
|
||||
|
||||
AbstractAnalysisServerIntegrationTest() {
|
||||
initializeInttestMixin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a future which will complete when a 'server.status' notification is
|
||||
* received from the server with 'analyzing' set to false.
|
||||
*
|
||||
* The future will only be completed by 'server.status' notifications that are
|
||||
* received after this function call. So it is safe to use this getter
|
||||
* multiple times in one test; each time it is used it will wait afresh for
|
||||
* analysis to finish.
|
||||
*/
|
||||
/// Return a future which will complete when a 'server.status' notification is
|
||||
/// received from the server with 'analyzing' set to false.
|
||||
///
|
||||
/// The future will only be completed by 'server.status' notifications that
|
||||
/// are received after this function call. So it is safe to use this getter
|
||||
/// multiple times in one test; each time it is used it will wait afresh for
|
||||
/// analysis to finish.
|
||||
Future<ServerStatusParams> get analysisFinished {
|
||||
Completer<ServerStatusParams> completer = Completer<ServerStatusParams>();
|
||||
StreamSubscription<ServerStatusParams> subscription;
|
||||
|
@ -157,10 +132,8 @@ abstract class AbstractAnalysisServerIntegrationTest
|
|||
return completer.future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print out any messages exchanged with the server. If some messages have
|
||||
* already been exchanged with the server, they are printed out immediately.
|
||||
*/
|
||||
/// Print out any messages exchanged with the server. If some messages have
|
||||
/// already been exchanged with the server, they are printed out immediately.
|
||||
void debugStdio() {
|
||||
server.debugStdio();
|
||||
}
|
||||
|
@ -168,9 +141,7 @@ abstract class AbstractAnalysisServerIntegrationTest
|
|||
List<AnalysisError> getErrors(String pathname) =>
|
||||
currentAnalysisErrors[pathname];
|
||||
|
||||
/**
|
||||
* Read a source file with the given absolute [pathname].
|
||||
*/
|
||||
/// Read a source file with the given absolute [pathname].
|
||||
String readFile(String pathname) => File(pathname).readAsStringSync();
|
||||
|
||||
@override
|
||||
|
@ -179,10 +150,8 @@ abstract class AbstractAnalysisServerIntegrationTest
|
|||
return super.sendServerSetSubscriptions(subscriptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* The server is automatically started before every test, and a temporary
|
||||
* [sourceDirectory] is created.
|
||||
*/
|
||||
/// The server is automatically started before every test, and a temporary
|
||||
/// [sourceDirectory] is created.
|
||||
Future setUp() async {
|
||||
sourceDirectory = Directory(Directory.systemTemp
|
||||
.createTempSync('analysisServer')
|
||||
|
@ -211,9 +180,7 @@ abstract class AbstractAnalysisServerIntegrationTest
|
|||
return serverConnected.future;
|
||||
}
|
||||
|
||||
/**
|
||||
* If [skipShutdown] is not set, shut down the server.
|
||||
*/
|
||||
/// If [skipShutdown] is not set, shut down the server.
|
||||
Future shutdownIfNeeded() {
|
||||
if (skipShutdown) {
|
||||
return Future.value();
|
||||
|
@ -228,21 +195,17 @@ abstract class AbstractAnalysisServerIntegrationTest
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given [relativePath] to an absolute path, by interpreting it
|
||||
* relative to [sourceDirectory]. On Windows any forward slashes in
|
||||
* [relativePath] are converted to backslashes.
|
||||
*/
|
||||
/// Convert the given [relativePath] to an absolute path, by interpreting it
|
||||
/// relative to [sourceDirectory]. On Windows any forward slashes in
|
||||
/// [relativePath] are converted to backslashes.
|
||||
String sourcePath(String relativePath) {
|
||||
return join(sourceDirectory.path, relativePath.replaceAll('/', separator));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the server an 'analysis.setAnalysisRoots' command directing it to
|
||||
* analyze [sourceDirectory]. If [subscribeStatus] is true (the default),
|
||||
* then also enable [SERVER_NOTIFICATION_STATUS] notifications so that
|
||||
* [analysisFinished] can be used.
|
||||
*/
|
||||
/// Send the server an 'analysis.setAnalysisRoots' command directing it to
|
||||
/// analyze [sourceDirectory]. If [subscribeStatus] is true (the default),
|
||||
/// then also enable [SERVER_NOTIFICATION_STATUS] notifications so that
|
||||
/// [analysisFinished] can be used.
|
||||
Future standardAnalysisSetup({bool subscribeStatus = true}) {
|
||||
List<Future> futures = <Future>[];
|
||||
if (subscribeStatus) {
|
||||
|
@ -252,9 +215,7 @@ abstract class AbstractAnalysisServerIntegrationTest
|
|||
return Future.wait(futures);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start [server].
|
||||
*/
|
||||
/// Start [server].
|
||||
Future startServer({
|
||||
int diagnosticPort,
|
||||
int servicesPort,
|
||||
|
@ -263,25 +224,21 @@ abstract class AbstractAnalysisServerIntegrationTest
|
|||
diagnosticPort: diagnosticPort, servicesPort: servicesPort);
|
||||
}
|
||||
|
||||
/**
|
||||
* After every test, the server is stopped and [sourceDirectory] is deleted.
|
||||
*/
|
||||
/// After every test, the server is stopped and [sourceDirectory] is deleted.
|
||||
Future tearDown() {
|
||||
return shutdownIfNeeded().then((_) {
|
||||
sourceDirectory.deleteSync(recursive: true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a source file with the given absolute [pathname] and [contents].
|
||||
*
|
||||
* If the file didn't previously exist, it is created. If it did, it is
|
||||
* overwritten.
|
||||
*
|
||||
* Parent directories are created as necessary.
|
||||
*
|
||||
* Return a normalized path to the file (with symbolic links resolved).
|
||||
*/
|
||||
/// Write a source file with the given absolute [pathname] and [contents].
|
||||
///
|
||||
/// If the file didn't previously exist, it is created. If it did, it is
|
||||
/// overwritten.
|
||||
///
|
||||
/// Parent directories are created as necessary.
|
||||
///
|
||||
/// Return a normalized path to the file (with symbolic links resolved).
|
||||
String writeFile(String pathname, String contents) {
|
||||
Directory(dirname(pathname)).createSync(recursive: true);
|
||||
File file = File(pathname);
|
||||
|
@ -290,22 +247,16 @@ abstract class AbstractAnalysisServerIntegrationTest
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for Matcher which doesn't create the underlying Matcher object
|
||||
* until it is needed. This is necessary in order to create matchers that can
|
||||
* refer to themselves (so that recursive data structures can be represented).
|
||||
*/
|
||||
/// Wrapper class for Matcher which doesn't create the underlying Matcher object
|
||||
/// until it is needed. This is necessary in order to create matchers that can
|
||||
/// refer to themselves (so that recursive data structures can be represented).
|
||||
class LazyMatcher implements Matcher {
|
||||
/**
|
||||
* Callback that will be used to create the matcher the first time it is
|
||||
* needed.
|
||||
*/
|
||||
/// Callback that will be used to create the matcher the first time it is
|
||||
/// needed.
|
||||
final MatcherCreator _creator;
|
||||
|
||||
/**
|
||||
* The matcher returned by [_creator], if it has already been called.
|
||||
* Otherwise null.
|
||||
*/
|
||||
/// The matcher returned by [_creator], if it has already been called.
|
||||
/// Otherwise null.
|
||||
Matcher _wrappedMatcher;
|
||||
|
||||
LazyMatcher(this._creator);
|
||||
|
@ -330,26 +281,18 @@ class LazyMatcher implements Matcher {
|
|||
return _wrappedMatcher.matches(item, matchState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the wrapped matcher object, if it hasn't been created already.
|
||||
*/
|
||||
/// Create the wrapped matcher object, if it hasn't been created already.
|
||||
void _createMatcher() {
|
||||
_wrappedMatcher ??= _creator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matcher that matches a String drawn from a limited set.
|
||||
*/
|
||||
/// Matcher that matches a String drawn from a limited set.
|
||||
class MatchesEnum extends Matcher {
|
||||
/**
|
||||
* Short description of the expected type.
|
||||
*/
|
||||
/// Short description of the expected type.
|
||||
final String description;
|
||||
|
||||
/**
|
||||
* The set of enum values that are allowed.
|
||||
*/
|
||||
/// The set of enum values that are allowed.
|
||||
final List<String> allowedValues;
|
||||
|
||||
const MatchesEnum(this.description, this.allowedValues);
|
||||
|
@ -364,26 +307,18 @@ class MatchesEnum extends Matcher {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matcher that matches a JSON object, with a given set of required and
|
||||
* optional fields, and their associated types (expressed as [Matcher]s).
|
||||
*/
|
||||
/// Matcher that matches a JSON object, with a given set of required and
|
||||
/// optional fields, and their associated types (expressed as [Matcher]s).
|
||||
class MatchesJsonObject extends _RecursiveMatcher {
|
||||
/**
|
||||
* Short description of the expected type.
|
||||
*/
|
||||
/// Short description of the expected type.
|
||||
final String description;
|
||||
|
||||
/**
|
||||
* Fields that are required to be in the JSON object, and [Matcher]s describing
|
||||
* their expected types.
|
||||
*/
|
||||
/// Fields that are required to be in the JSON object, and [Matcher]s
|
||||
/// describing their expected types.
|
||||
final Map<String, Matcher> requiredFields;
|
||||
|
||||
/**
|
||||
* Fields that are optional in the JSON object, and [Matcher]s describing
|
||||
* their expected types.
|
||||
*/
|
||||
/// Fields that are optional in the JSON object, and [Matcher]s describing
|
||||
/// their expected types.
|
||||
final Map<String, Matcher> optionalFields;
|
||||
|
||||
const MatchesJsonObject(this.description, this.requiredFields,
|
||||
|
@ -427,11 +362,9 @@ class MatchesJsonObject extends _RecursiveMatcher {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the type of a field called [key], having value [value], using
|
||||
* [valueMatcher]. If it doesn't match, record a closure in [mismatches]
|
||||
* which can describe the mismatch.
|
||||
*/
|
||||
/// Check the type of a field called [key], having value [value], using
|
||||
/// [valueMatcher]. If it doesn't match, record a closure in [mismatches]
|
||||
/// which can describe the mismatch.
|
||||
void _checkField(String key, value, Matcher valueMatcher,
|
||||
List<MismatchDescriber> mismatches) {
|
||||
checkSubstructure(
|
||||
|
@ -443,73 +376,49 @@ class MatchesJsonObject extends _RecursiveMatcher {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instances of the class [Server] manage a connection to a server process, and
|
||||
* facilitate communication to and from the server.
|
||||
*/
|
||||
/// Instances of the class [Server] manage a connection to a server process, and
|
||||
/// facilitate communication to and from the server.
|
||||
class Server {
|
||||
/**
|
||||
* Server process object, or null if server hasn't been started yet.
|
||||
*/
|
||||
/// Server process object, or null if server hasn't been started yet.
|
||||
Process _process;
|
||||
|
||||
/**
|
||||
* Commands that have been sent to the server but not yet acknowledged, and
|
||||
* the [Completer] objects which should be completed when acknowledgement is
|
||||
* received.
|
||||
*/
|
||||
/// Commands that have been sent to the server but not yet acknowledged, and
|
||||
/// the [Completer] objects which should be completed when acknowledgement is
|
||||
/// received.
|
||||
final Map<String, Completer<Map<String, dynamic>>> _pendingCommands =
|
||||
<String, Completer<Map<String, dynamic>>>{};
|
||||
|
||||
/**
|
||||
* Number which should be used to compute the 'id' to send in the next command
|
||||
* sent to the server.
|
||||
*/
|
||||
/// Number which should be used to compute the 'id' to send in the next
|
||||
/// command sent to the server.
|
||||
int _nextId = 0;
|
||||
|
||||
/**
|
||||
* Messages which have been exchanged with the server; we buffer these
|
||||
* up until the test finishes, so that they can be examined in the debugger
|
||||
* or printed out in response to a call to [debugStdio].
|
||||
*/
|
||||
/// Messages which have been exchanged with the server; we buffer these
|
||||
/// up until the test finishes, so that they can be examined in the debugger
|
||||
/// or printed out in response to a call to [debugStdio].
|
||||
final List<String> _recordedStdio = <String>[];
|
||||
|
||||
/**
|
||||
* True if we are currently printing out messages exchanged with the server.
|
||||
*/
|
||||
/// True if we are currently printing out messages exchanged with the server.
|
||||
bool _debuggingStdio = false;
|
||||
|
||||
/**
|
||||
* True if we've received bad data from the server, and we are aborting the
|
||||
* test.
|
||||
*/
|
||||
/// True if we've received bad data from the server, and we are aborting the
|
||||
/// test.
|
||||
bool _receivedBadDataFromServer = false;
|
||||
|
||||
/**
|
||||
* Stopwatch that we use to generate timing information for debug output.
|
||||
*/
|
||||
/// Stopwatch that we use to generate timing information for debug output.
|
||||
final Stopwatch _time = Stopwatch();
|
||||
|
||||
/**
|
||||
* The [currentElapseTime] at which the last communication was received from the server
|
||||
* or `null` if no communication has been received.
|
||||
*/
|
||||
/// The [currentElapseTime] at which the last communication was received from
|
||||
/// the server or `null` if no communication has been received.
|
||||
double lastCommunicationTime;
|
||||
|
||||
/**
|
||||
* The current elapse time (seconds) since the server was started.
|
||||
*/
|
||||
/// The current elapse time (seconds) since the server was started.
|
||||
double get currentElapseTime => _time.elapsedTicks / _time.frequency;
|
||||
|
||||
/**
|
||||
* Future that completes when the server process exits.
|
||||
*/
|
||||
/// Future that completes when the server process exits.
|
||||
Future<int> get exitCode => _process.exitCode;
|
||||
|
||||
/**
|
||||
* Print out any messages exchanged with the server. If some messages have
|
||||
* already been exchanged with the server, they are printed out immediately.
|
||||
*/
|
||||
/// Print out any messages exchanged with the server. If some messages have
|
||||
/// already been exchanged with the server, they are printed out immediately.
|
||||
void debugStdio() {
|
||||
if (_debuggingStdio) {
|
||||
return;
|
||||
|
@ -520,10 +429,8 @@ class Server {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the root directory of the analysis_server package by proceeding
|
||||
* upward to the 'test' dir, and then going up one more directory.
|
||||
*/
|
||||
/// Find the root directory of the analysis_server package by proceeding
|
||||
/// upward to the 'test' dir, and then going up one more directory.
|
||||
String findRoot(String pathname) {
|
||||
while (!['benchmark', 'test'].contains(basename(pathname))) {
|
||||
String parent = dirname(pathname);
|
||||
|
@ -535,17 +442,13 @@ class Server {
|
|||
return dirname(pathname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a future that will complete when all commands that have been sent
|
||||
* to the server so far have been flushed to the OS buffer.
|
||||
*/
|
||||
/// Return a future that will complete when all commands that have been sent
|
||||
/// to the server so far have been flushed to the OS buffer.
|
||||
Future flushCommands() {
|
||||
return _process.stdin.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the server.
|
||||
*/
|
||||
/// Stop the server.
|
||||
Future<int> kill(String reason) {
|
||||
debugStdio();
|
||||
_recordStdio('FORCIBLY TERMINATING PROCESS: $reason');
|
||||
|
@ -553,10 +456,8 @@ class Server {
|
|||
return _process.exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening to output from the server, and deliver notifications to
|
||||
* [notificationProcessor].
|
||||
*/
|
||||
/// Start listening to output from the server, and deliver notifications to
|
||||
/// [notificationProcessor].
|
||||
void listenToOutput(NotificationProcessor notificationProcessor) {
|
||||
_process.stdout
|
||||
.transform(utf8.decoder)
|
||||
|
@ -627,14 +528,12 @@ class Server {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a command to the server. An 'id' will be automatically assigned.
|
||||
* The returned [Future] will be completed when the server acknowledges the
|
||||
* command with a response. If the server acknowledges the command with a
|
||||
* normal (non-error) response, the future will be completed with the 'result'
|
||||
* field from the response. If the server acknowledges the command with an
|
||||
* error response, the future will be completed with an error.
|
||||
*/
|
||||
/// Send a command to the server. An 'id' will be automatically assigned.
|
||||
/// The returned [Future] will be completed when the server acknowledges the
|
||||
/// command with a response. If the server acknowledges the command with a
|
||||
/// normal (non-error) response, the future will be completed with the
|
||||
/// 'result' field from the response. If the server acknowledges the command
|
||||
/// with an error response, the future will be completed with an error.
|
||||
Future<Map<String, dynamic>> send(
|
||||
String method, Map<String, dynamic> params) {
|
||||
String id = '${_nextId++}';
|
||||
|
@ -654,11 +553,9 @@ class Server {
|
|||
return completer.future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server. If [profileServer] is `true`, the server will be started
|
||||
* with "--observe" and "--pause-isolates-on-exit", allowing the observatory
|
||||
* to be used.
|
||||
*/
|
||||
/// Start the server. If [profileServer] is `true`, the server will be started
|
||||
/// with "--observe" and "--pause-isolates-on-exit", allowing the observatory
|
||||
/// to be used.
|
||||
Future start({
|
||||
int diagnosticPort,
|
||||
String instrumentationLogFile,
|
||||
|
@ -741,9 +638,7 @@ class Server {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deal with bad data received from the server.
|
||||
*/
|
||||
/// Deal with bad data received from the server.
|
||||
void _badDataFromServer(String details, {bool silent = false}) {
|
||||
if (!silent) {
|
||||
_recordStdio('BAD DATA FROM SERVER: $details');
|
||||
|
@ -764,10 +659,8 @@ class Server {
|
|||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a message that was exchanged with the server, and print it out if
|
||||
* [debugStdio] has been called.
|
||||
*/
|
||||
/// Record a message that was exchanged with the server, and print it out if
|
||||
/// [debugStdio] has been called.
|
||||
void _recordStdio(String line) {
|
||||
double elapsedTime = currentElapseTime;
|
||||
line = '$elapsedTime: $line';
|
||||
|
@ -778,9 +671,7 @@ class Server {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An error result from a server request.
|
||||
*/
|
||||
/// An error result from a server request.
|
||||
class ServerErrorMessage {
|
||||
final Map message;
|
||||
|
||||
|
@ -792,19 +683,13 @@ class ServerErrorMessage {
|
|||
String toString() => message.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Matcher that matches a list of objects, each of which satisfies the given
|
||||
* matcher.
|
||||
*/
|
||||
/// Matcher that matches a list of objects, each of which satisfies the given
|
||||
/// matcher.
|
||||
class _ListOf extends Matcher {
|
||||
/**
|
||||
* Matcher which every element of the list must satisfy.
|
||||
*/
|
||||
/// Matcher which every element of the list must satisfy.
|
||||
final Matcher elementMatcher;
|
||||
|
||||
/**
|
||||
* Iterable matcher which we use to test the contents of the list.
|
||||
*/
|
||||
/// Iterable matcher which we use to test the contents of the list.
|
||||
final Matcher iterableMatcher;
|
||||
|
||||
_ListOf(elementMatcher)
|
||||
|
@ -836,19 +721,13 @@ class _ListOf extends Matcher {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matcher that matches a map of objects, where each key/value pair in the
|
||||
* map satisies the given key and value matchers.
|
||||
*/
|
||||
/// Matcher that matches a map of objects, where each key/value pair in the
|
||||
/// map satisies the given key and value matchers.
|
||||
class _MapOf extends _RecursiveMatcher {
|
||||
/**
|
||||
* Matcher which every key in the map must satisfy.
|
||||
*/
|
||||
/// Matcher which every key in the map must satisfy.
|
||||
final Matcher keyMatcher;
|
||||
|
||||
/**
|
||||
* Matcher which every value in the map must satisfy.
|
||||
*/
|
||||
/// Matcher which every value in the map must satisfy.
|
||||
final Matcher valueMatcher;
|
||||
|
||||
_MapOf(this.keyMatcher, this.valueMatcher);
|
||||
|
@ -883,14 +762,10 @@ class _MapOf extends _RecursiveMatcher {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matcher that matches a union of different types, each of which is described
|
||||
* by a matcher.
|
||||
*/
|
||||
/// Matcher that matches a union of different types, each of which is described
|
||||
/// by a matcher.
|
||||
class _OneOf extends Matcher {
|
||||
/**
|
||||
* Matchers for the individual choices.
|
||||
*/
|
||||
/// Matchers for the individual choices.
|
||||
final List<Matcher> choiceMatchers;
|
||||
|
||||
_OneOf(this.choiceMatchers);
|
||||
|
@ -925,19 +800,15 @@ class _OneOf extends Matcher {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for matchers that operate by recursing through the contents of
|
||||
* an object.
|
||||
*/
|
||||
/// Base class for matchers that operate by recursing through the contents of
|
||||
/// an object.
|
||||
abstract class _RecursiveMatcher extends Matcher {
|
||||
const _RecursiveMatcher();
|
||||
|
||||
/**
|
||||
* Check the type of a substructure whose value is [item], using [matcher].
|
||||
* If it doesn't match, record a closure in [mismatches] which can describe
|
||||
* the mismatch. [describeSubstructure] is used to describe which
|
||||
* substructure did not match.
|
||||
*/
|
||||
/// Check the type of a substructure whose value is [item], using [matcher].
|
||||
/// If it doesn't match, record a closure in [mismatches] which can describe
|
||||
/// the mismatch. [describeSubstructure] is used to describe which
|
||||
/// substructure did not match.
|
||||
void checkSubstructure(
|
||||
item,
|
||||
Matcher matcher,
|
||||
|
@ -1000,15 +871,11 @@ abstract class _RecursiveMatcher extends Matcher {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate [mismatches] with descriptions of all the ways in which [item]
|
||||
* does not match.
|
||||
*/
|
||||
/// Populate [mismatches] with descriptions of all the ways in which [item]
|
||||
/// does not match.
|
||||
void populateMismatches(item, List<MismatchDescriber> mismatches);
|
||||
|
||||
/**
|
||||
* Create a [MismatchDescriber] describing a mismatch with a simple string.
|
||||
*/
|
||||
/// Create a [MismatchDescriber] describing a mismatch with a simple string.
|
||||
MismatchDescriber simpleDescription(String description) =>
|
||||
(Description mismatchDescription) {
|
||||
mismatchDescription.add(description);
|
||||
|
|
|
@ -309,25 +309,19 @@ mixin LspAnalysisServerTestMixin implements ClientCapabilitiesHelperMixin {
|
|||
final startOfDocPos = Position(0, 0);
|
||||
final startOfDocRange = Range(Position(0, 0), Position(0, 0));
|
||||
|
||||
/**
|
||||
* A stream of [NotificationMessage]s from the server that may be errors.
|
||||
*/
|
||||
/// A stream of [NotificationMessage]s from the server that may be errors.
|
||||
Stream<NotificationMessage> get errorNotificationsFromServer {
|
||||
return notificationsFromServer.where(_isErrorNotification);
|
||||
}
|
||||
|
||||
/**
|
||||
* A stream of [NotificationMessage]s from the server.
|
||||
*/
|
||||
/// A stream of [NotificationMessage]s from the server.
|
||||
Stream<NotificationMessage> get notificationsFromServer {
|
||||
return serverToClient
|
||||
.where((m) => m is NotificationMessage)
|
||||
.cast<NotificationMessage>();
|
||||
}
|
||||
|
||||
/**
|
||||
* A stream of [RequestMessage]s from the server.
|
||||
*/
|
||||
/// A stream of [RequestMessage]s from the server.
|
||||
Stream<RequestMessage> get requestsFromServer {
|
||||
return serverToClient
|
||||
.where((m) => m is RequestMessage)
|
||||
|
|
|
@ -18,22 +18,16 @@ import 'package:test/test.dart';
|
|||
|
||||
const _jsonEncoder = JsonEncoder.withIndent(' ');
|
||||
|
||||
/**
|
||||
* A [Matcher] that check that the given [Response] has an expected identifier
|
||||
* and has an error. The error code may optionally be checked.
|
||||
*/
|
||||
/// A [Matcher] that check that the given [Response] has an expected identifier
|
||||
/// and has an error. The error code may optionally be checked.
|
||||
Matcher isResponseFailure(String id, [RequestErrorCode code]) =>
|
||||
_IsResponseFailure(id, code);
|
||||
|
||||
/**
|
||||
* A [Matcher] that check that the given [Response] has an expected identifier
|
||||
* and no error.
|
||||
*/
|
||||
/// A [Matcher] that check that the given [Response] has an expected identifier
|
||||
/// and no error.
|
||||
Matcher isResponseSuccess(String id) => _IsResponseSuccess(id);
|
||||
|
||||
/**
|
||||
* A mock [LspServerCommunicationChannel] for testing [LspAnalysisServer].
|
||||
*/
|
||||
/// A mock [LspServerCommunicationChannel] for testing [LspAnalysisServer].
|
||||
class MockLspServerChannel implements LspServerCommunicationChannel {
|
||||
final StreamController<lsp.Message> _clientToServer =
|
||||
StreamController<lsp.Message>.broadcast();
|
||||
|
@ -42,9 +36,7 @@ class MockLspServerChannel implements LspServerCommunicationChannel {
|
|||
|
||||
String name;
|
||||
|
||||
/**
|
||||
* Completer that will be signalled when the input stream is closed.
|
||||
*/
|
||||
/// Completer that will be signalled when the input stream is closed.
|
||||
final Completer _closed = Completer();
|
||||
|
||||
MockLspServerChannel(bool _printMessages) {
|
||||
|
@ -56,9 +48,7 @@ class MockLspServerChannel implements LspServerCommunicationChannel {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Future that will be completed when the input stream is closed.
|
||||
*/
|
||||
/// Future that will be completed when the input stream is closed.
|
||||
@override
|
||||
Future get closed {
|
||||
return _closed.future;
|
||||
|
@ -122,11 +112,9 @@ class MockLspServerChannel implements LspServerCommunicationChannel {
|
|||
_serverToClient.add(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the given [request] to the server and return a future that will
|
||||
* complete when a response associated with the [request] has been received.
|
||||
* The value of the future will be the received response.
|
||||
*/
|
||||
/// Send the given [request] to the server and return a future that will
|
||||
/// complete when a response associated with the [request] has been received.
|
||||
/// The value of the future will be the received response.
|
||||
Future<lsp.ResponseMessage> sendRequestToServer(lsp.RequestMessage request) {
|
||||
// No further requests should be sent after the connection is closed.
|
||||
if (_closed.isCompleted) {
|
||||
|
@ -164,15 +152,13 @@ class MockLspServerChannel implements LspServerCommunicationChannel {
|
|||
_clientToServer.add(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a future that will complete when a response associated with the
|
||||
* given [request] has been received. The value of the future will be the
|
||||
* received response. The returned future will throw an exception if a server
|
||||
* error is reported before the response has been received.
|
||||
*
|
||||
* Unlike [sendLspRequest], this method assumes that the [request] has already
|
||||
* been sent to the server.
|
||||
*/
|
||||
/// Return a future that will complete when a response associated with the
|
||||
/// given [request] has been received. The value of the future will be the
|
||||
/// received response. The returned future will throw an exception if a server
|
||||
/// error is reported before the response has been received.
|
||||
///
|
||||
/// Unlike [sendLspRequest], this method assumes that the [request] has
|
||||
/// already been sent to the server.
|
||||
Future<lsp.ResponseMessage> waitForResponse(
|
||||
lsp.RequestMessage request, {
|
||||
bool throwOnError = true,
|
||||
|
@ -252,9 +238,7 @@ class StringTypedMock {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A [Matcher] that check that there are no `error` in a given [Response].
|
||||
*/
|
||||
/// A [Matcher] that check that there are no `error` in a given [Response].
|
||||
class _IsResponseFailure extends Matcher {
|
||||
final String _id;
|
||||
final RequestErrorCode _code;
|
||||
|
@ -300,9 +284,7 @@ class _IsResponseFailure extends Matcher {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A [Matcher] that check that there are no `error` in a given [Response].
|
||||
*/
|
||||
/// A [Matcher] that check that there are no `error` in a given [Response].
|
||||
class _IsResponseSuccess extends Matcher {
|
||||
final String _id;
|
||||
|
||||
|
|
|
@ -6,9 +6,6 @@ import 'package:test_reflective_loader/test_reflective_loader.dart';
|
|||
|
||||
import 'protocol_dart_test.dart' as protocol_dart_test;
|
||||
|
||||
/**
|
||||
* Utility for manually running all tests.
|
||||
*/
|
||||
void main() {
|
||||
defineReflectiveSuite(() {
|
||||
protocol_dart_test.main();
|
||||
|
|
|
@ -243,19 +243,15 @@ class EnumTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for testing the correspondence between an analysis engine enum
|
||||
* and an analysis server API enum.
|
||||
*/
|
||||
/// Helper class for testing the correspondence between an analysis engine enum
|
||||
/// and an analysis server API enum.
|
||||
class EnumTester<EngineEnum, ApiEnum> {
|
||||
/**
|
||||
* Test that the function [convert] properly converts all possible values of
|
||||
* [EngineEnum] to an [ApiEnum] with the same name, with the exceptions noted
|
||||
* in [exceptions]. For each key in [exceptions], if the corresponding value
|
||||
* is null, then we check that converting the given key results in an error.
|
||||
* If the corresponding value is an [ApiEnum], then we check that converting
|
||||
* the given key results in the given value.
|
||||
*/
|
||||
/// Test that the function [convert] properly converts all possible values of
|
||||
/// [EngineEnum] to an [ApiEnum] with the same name, with the exceptions noted
|
||||
/// in [exceptions]. For each key in [exceptions], if the corresponding value
|
||||
/// is null, then we check that converting the given key results in an error.
|
||||
/// If the corresponding value is an [ApiEnum], then we check that converting
|
||||
/// the given key results in the given value.
|
||||
void run(ApiEnum Function(EngineEnum) convert,
|
||||
{Map<EngineEnum, ApiEnum> exceptions = const {}}) {
|
||||
ClassMirror engineClass = reflectClass(EngineEnum);
|
||||
|
|
|
@ -27,10 +27,8 @@ class ArgListContributorTest extends DartCompletionContributorTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that there is a suggestion with the given parameter [name] that has
|
||||
* the given [completion], [selectionOffset] and [selectionLength].
|
||||
*/
|
||||
/// Assert that there is a suggestion with the given parameter [name] that has
|
||||
/// the given [completion], [selectionOffset] and [selectionLength].
|
||||
void assertSuggestArgumentAndCompletion(String name,
|
||||
{String completion, int selectionOffset, int selectionLength = 0}) {
|
||||
CompletionSuggestion suggestion =
|
||||
|
@ -71,10 +69,8 @@ class ArgListContributorTest extends DartCompletionContributorTest {
|
|||
fail(msg.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the specified named argument suggestions with their types are
|
||||
* the only suggestions.
|
||||
*/
|
||||
/// Assert that the specified named argument suggestions with their types are
|
||||
/// the only suggestions.
|
||||
void assertSuggestArgumentsAndTypes(
|
||||
{Map<String, String> namedArgumentsWithTypes,
|
||||
List<int> requiredParamIndices = const <int>[],
|
||||
|
@ -102,9 +98,7 @@ class ArgListContributorTest extends DartCompletionContributorTest {
|
|||
assertNoOtherSuggestions(expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the specified suggestions are the only suggestions.
|
||||
*/
|
||||
/// Assert that the specified suggestions are the only suggestions.
|
||||
void assertSuggestions(List<String> suggestions) {
|
||||
List<CompletionSuggestion> expected = <CompletionSuggestion>[];
|
||||
for (String suggestion in suggestions) {
|
||||
|
|
|
@ -104,18 +104,15 @@ abstract class _BaseDartCompletionContributorTest extends AbstractContextTest {
|
|||
|
||||
List<CompletionSuggestion> suggestions;
|
||||
|
||||
/**
|
||||
* If `true` and `null` is specified as the suggestion's expected returnType
|
||||
* then the actual suggestion is expected to have a `dynamic` returnType.
|
||||
* Newer tests return `false` so that they can distinguish between
|
||||
* `dynamic` and `null`.
|
||||
* Eventually all tests should be converted and this getter removed.
|
||||
*/
|
||||
/// If `true` and `null` is specified as the suggestion's expected returnType
|
||||
/// then the actual suggestion is expected to have a `dynamic` returnType.
|
||||
/// Newer tests return `false` so that they can distinguish between
|
||||
/// `dynamic` and `null`.
|
||||
/// Eventually all tests should be converted and this getter removed.
|
||||
bool get isNullExpectedReturnTypeConsideredDynamic => true;
|
||||
/**
|
||||
* Return `true` if contributors should suggest constructors in contexts where
|
||||
* there is no `new` or `const` keyword.
|
||||
*/
|
||||
|
||||
/// Return `true` if contributors should suggest constructors in contexts
|
||||
/// where there is no `new` or `const` keyword.
|
||||
bool get suggestConstructorsWithoutNew => true;
|
||||
|
||||
bool get usingFastaParser => analyzer.Parser.useFasta;
|
||||
|
|
|
@ -21,12 +21,10 @@ void main() {
|
|||
|
||||
@reflectiveTest
|
||||
class TypeMemberContributorTest extends DartCompletionContributorTest {
|
||||
/**
|
||||
* Check whether a declaration of the form [shadower] in a derived class
|
||||
* shadows a declaration of the form [shadowee] in a base class, for the
|
||||
* purposes of what is shown during completion. [shouldBeShadowed] indicates
|
||||
* whether shadowing is expected.
|
||||
*/
|
||||
/// Check whether a declaration of the form [shadower] in a derived class
|
||||
/// shadows a declaration of the form [shadowee] in a base class, for the
|
||||
/// purposes of what is shown during completion. [shouldBeShadowed] indicates
|
||||
/// whether shadowing is expected.
|
||||
Future check_shadowing(
|
||||
String shadower, String shadowee, bool shouldBeShadowed) async {
|
||||
addTestSource('''
|
||||
|
|
|
@ -35,9 +35,7 @@ int findIdentifierLength(String search) {
|
|||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base class for all [Refactoring] tests.
|
||||
*/
|
||||
/// The base class for all [Refactoring] tests.
|
||||
abstract class RefactoringTest extends AbstractSingleUnitTest {
|
||||
SearchEngine searchEngine;
|
||||
|
||||
|
@ -45,10 +43,8 @@ abstract class RefactoringTest extends AbstractSingleUnitTest {
|
|||
|
||||
Refactoring get refactoring;
|
||||
|
||||
/**
|
||||
* Asserts that [refactoringChange] contains a [FileEdit] for the file
|
||||
* with the given [path], and it results the [expectedCode].
|
||||
*/
|
||||
/// Asserts that [refactoringChange] contains a [FileEdit] for the file
|
||||
/// with the given [path], and it results the [expectedCode].
|
||||
void assertFileChangeResult(String path, String expectedCode) {
|
||||
// prepare FileEdit
|
||||
SourceFileEdit fileEdit = refactoringChange.getFileEdit(convertPath(path));
|
||||
|
@ -60,18 +56,14 @@ abstract class RefactoringTest extends AbstractSingleUnitTest {
|
|||
expect(actualCode, expectedCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that [refactoringChange] does not contain a [FileEdit] for the file
|
||||
* with the given [path].
|
||||
*/
|
||||
/// Asserts that [refactoringChange] does not contain a [FileEdit] for the
|
||||
/// file with the given [path].
|
||||
void assertNoFileChange(String path) {
|
||||
SourceFileEdit fileEdit = refactoringChange.getFileEdit(path);
|
||||
expect(fileEdit, isNull);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that [refactoring] initial/final conditions status is OK.
|
||||
*/
|
||||
/// Asserts that [refactoring] initial/final conditions status is OK.
|
||||
Future assertRefactoringConditionsOK() async {
|
||||
RefactoringStatus status = await refactoring.checkInitialConditions();
|
||||
assertRefactoringStatusOK(status);
|
||||
|
@ -79,17 +71,13 @@ abstract class RefactoringTest extends AbstractSingleUnitTest {
|
|||
assertRefactoringStatusOK(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that [refactoring] final conditions status is OK.
|
||||
*/
|
||||
/// Asserts that [refactoring] final conditions status is OK.
|
||||
Future assertRefactoringFinalConditionsOK() async {
|
||||
RefactoringStatus status = await refactoring.checkFinalConditions();
|
||||
assertRefactoringStatusOK(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that [status] has expected severity and message.
|
||||
*/
|
||||
/// Asserts that [status] has expected severity and message.
|
||||
void assertRefactoringStatus(
|
||||
RefactoringStatus status, RefactoringProblemSeverity expectedSeverity,
|
||||
{String expectedMessage,
|
||||
|
@ -115,17 +103,13 @@ abstract class RefactoringTest extends AbstractSingleUnitTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that [refactoring] status is OK.
|
||||
*/
|
||||
/// 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].
|
||||
*/
|
||||
/// 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();
|
||||
SourceChange change = await refactoring.createChange();
|
||||
|
@ -133,10 +117,8 @@ abstract class RefactoringTest extends AbstractSingleUnitTest {
|
|||
assertTestChangeResult(expectedCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that [refactoringChange] contains a [FileEdit] for [testFile], and
|
||||
* it results the [expectedCode].
|
||||
*/
|
||||
/// Asserts that [refactoringChange] contains a [FileEdit] for [testFile], and
|
||||
/// it results the [expectedCode].
|
||||
void assertTestChangeResult(String expectedCode) {
|
||||
// prepare FileEdit
|
||||
SourceFileEdit fileEdit = refactoringChange.getFileEdit(testFile);
|
||||
|
|
|
@ -11,17 +11,13 @@ import 'package:test/test.dart';
|
|||
|
||||
import 'abstract_refactoring.dart';
|
||||
|
||||
/**
|
||||
* The base class for all [RenameRefactoring] tests.
|
||||
*/
|
||||
/// The base class for all [RenameRefactoring] tests.
|
||||
class RenameRefactoringTest extends RefactoringTest {
|
||||
@override
|
||||
RenameRefactoring refactoring;
|
||||
|
||||
/**
|
||||
* Asserts that [refactoring] has potential edits in [testFile] at offset
|
||||
* of the given [searches].
|
||||
*/
|
||||
/// Asserts that [refactoring] has potential edits in [testFile] at offset
|
||||
/// of the given [searches].
|
||||
void assertPotentialEdits(List<String> searches) {
|
||||
Set<int> expectedOffsets = <int>{};
|
||||
for (String search in searches) {
|
||||
|
@ -38,10 +34,8 @@ class RenameRefactoringTest extends RefactoringTest {
|
|||
expect(expectedOffsets, isEmpty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new [RenameRefactoring] in [refactoring] for the [Element] of
|
||||
* the [SimpleIdentifier] at the given [search] pattern.
|
||||
*/
|
||||
/// Creates a new [RenameRefactoring] in [refactoring] for the [Element] of
|
||||
/// the [SimpleIdentifier] at the given [search] pattern.
|
||||
void createRenameRefactoringAtString(String search) {
|
||||
SimpleIdentifier identifier = findIdentifier(search);
|
||||
Element element = identifier.staticElement;
|
||||
|
@ -51,19 +45,15 @@ class RenameRefactoringTest extends RefactoringTest {
|
|||
createRenameRefactoringForElement(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new [RenameRefactoring] in [refactoring] for [element].
|
||||
* Fails if no [RenameRefactoring] can be created.
|
||||
*/
|
||||
/// Creates a new [RenameRefactoring] in [refactoring] for [element].
|
||||
/// Fails if no [RenameRefactoring] can be created.
|
||||
void createRenameRefactoringForElement(Element element) {
|
||||
var workspace = RefactoringWorkspace([driver], searchEngine);
|
||||
refactoring = RenameRefactoring(workspace, testAnalysisResult, element);
|
||||
expect(refactoring, isNotNull, reason: "No refactoring for '$element'.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the [Edit] with the given [id], maybe `null`.
|
||||
*/
|
||||
/// Returns the [Edit] with the given [id], maybe `null`.
|
||||
SourceEdit findEditById(String id) {
|
||||
for (SourceFileEdit fileEdit in refactoringChange.edits) {
|
||||
for (SourceEdit edit in fileEdit.edits) {
|
||||
|
|
|
@ -135,10 +135,8 @@ main() {
|
|||
expectedMessage: message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all conditions are OK and the result of applying [refactoring]
|
||||
* change to [testUnit] is [expectedCode].
|
||||
*/
|
||||
/// Checks that all conditions are OK and the result of applying [refactoring]
|
||||
/// change to [testUnit] is [expectedCode].
|
||||
Future _assertSuccessfulRefactoring(String expectedCode) async {
|
||||
await assertRefactoringConditionsOK();
|
||||
SourceChange refactoringChange = await refactoring.createChange();
|
||||
|
|
|
@ -189,10 +189,8 @@ void test() {}
|
|||
expectedMessage: message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all conditions are OK and the result of applying the [Change]
|
||||
* to [testUnit] is [expectedCode].
|
||||
*/
|
||||
/// Checks that all conditions are OK and the result of applying the [Change]
|
||||
/// to [testUnit] is [expectedCode].
|
||||
Future _assertSuccessfulRefactoring(String expectedCode) async {
|
||||
await assertRefactoringConditionsOK();
|
||||
SourceChange refactoringChange = await refactoring.createChange();
|
||||
|
|
|
@ -1235,11 +1235,9 @@ String foo() => '';
|
|||
''');
|
||||
}
|
||||
|
||||
/**
|
||||
* Here we use knowledge how exactly `1 + 2 + 3 + 4` is parsed. We know that
|
||||
* `1 + 2` will be a separate and complete binary expression, so it can be
|
||||
* handled as a single expression.
|
||||
*/
|
||||
/// Here we use knowledge how exactly `1 + 2 + 3 + 4` is parsed. We know that
|
||||
/// `1 + 2` will be a separate and complete binary expression, so it can be
|
||||
/// handled as a single expression.
|
||||
Future<void> test_singleExpression_partOfBinaryExpression() async {
|
||||
await indexTestUnit('''
|
||||
main() {
|
||||
|
@ -1386,10 +1384,8 @@ main() {
|
|||
expect(editGroups.first.toJson(), json.decode(expectedJsonString));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all conditions are OK and the result of applying the
|
||||
* [SourceChange] to [testUnit] is [expectedCode].
|
||||
*/
|
||||
/// Checks that all conditions are OK and the result of applying the
|
||||
/// [SourceChange] to [testUnit] is [expectedCode].
|
||||
Future _assertSuccessfulRefactoring(String expectedCode) async {
|
||||
await assertRefactoringConditionsOK();
|
||||
SourceChange refactoringChange = await refactoring.createChange();
|
||||
|
@ -1402,20 +1398,16 @@ main() {
|
|||
refactoring.name = 'res';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new refactoring in [refactoring] at the offset of the given
|
||||
* [search] pattern, and with the length `0`.
|
||||
*/
|
||||
/// Creates a new refactoring in [refactoring] at the offset of the given
|
||||
/// [search] pattern, and with the length `0`.
|
||||
void _createRefactoringAtString(String search) {
|
||||
int offset = findOffset(search);
|
||||
int length = 0;
|
||||
_createRefactoring(offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new refactoring in [refactoring] for the selection range of the
|
||||
* given [search] pattern.
|
||||
*/
|
||||
/// Creates a new refactoring in [refactoring] for the selection range of the
|
||||
/// given [search] pattern.
|
||||
void _createRefactoringForString(String search) {
|
||||
int offset = findOffset(search);
|
||||
int length = search.length;
|
||||
|
|
|
@ -2271,9 +2271,7 @@ res() {
|
|||
''');
|
||||
}
|
||||
|
||||
/**
|
||||
* We should always add ";" when invoke method with extracted statements.
|
||||
*/
|
||||
/// We should always add ";" when invoke method with extracted statements.
|
||||
Future<void> test_statements_endsWithBlock() async {
|
||||
await indexTestUnit('''
|
||||
main() {
|
||||
|
@ -2852,10 +2850,8 @@ int res() {
|
|||
''');
|
||||
}
|
||||
|
||||
/**
|
||||
* We have 3 identical statements, but select only 2.
|
||||
* This should not cause problems.
|
||||
*/
|
||||
/// We have 3 identical statements, but select only 2.
|
||||
/// This should not cause problems.
|
||||
Future<void> test_statements_twoOfThree() async {
|
||||
await indexTestUnit('''
|
||||
main() {
|
||||
|
@ -2915,10 +2911,8 @@ Completer<int> newCompleter() => null;
|
|||
assertTestChangeResult(expectedCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all conditions are OK and the result of applying the [Change]
|
||||
* to [testUnit] is [expectedCode].
|
||||
*/
|
||||
/// Checks that all conditions are OK and the result of applying the [Change]
|
||||
/// to [testUnit] is [expectedCode].
|
||||
Future _assertSuccessfulRefactoring(String expectedCode) async {
|
||||
await assertRefactoringConditionsOK();
|
||||
refactoring.createGetter = false;
|
||||
|
@ -2944,20 +2938,16 @@ Completer<int> newCompleter() => null;
|
|||
_createRefactoring(offset, end - offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new refactoring in [refactoring] for the selection range of the
|
||||
* given [search] pattern.
|
||||
*/
|
||||
/// Creates a new refactoring in [refactoring] for the selection range of the
|
||||
/// given [search] pattern.
|
||||
void _createRefactoringForString(String search) {
|
||||
int offset = findOffset(search);
|
||||
int length = search.length;
|
||||
_createRefactoring(offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new refactoring in [refactoring] at the offset of the given
|
||||
* [search] pattern, and with `0` length.
|
||||
*/
|
||||
/// Creates a new refactoring in [refactoring] at the offset of the given
|
||||
/// [search] pattern, and with `0` length.
|
||||
void _createRefactoringForStringOffset(String search) {
|
||||
int offset = findOffset(search);
|
||||
_createRefactoring(offset, 0);
|
||||
|
@ -2969,11 +2959,9 @@ Completer<int> newCompleter() => null;
|
|||
_createRefactoring(offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a deep copy of [refactoring] parameters.
|
||||
* There was a bug masked by updating parameter instances shared between the
|
||||
* refactoring and the test.
|
||||
*/
|
||||
/// Returns a deep copy of [refactoring] parameters.
|
||||
/// There was a bug masked by updating parameter instances shared between the
|
||||
/// refactoring and the test.
|
||||
List<RefactoringMethodParameter> _getParametersCopy() {
|
||||
return refactoring.parameters.map((p) {
|
||||
return RefactoringMethodParameter(p.kind, p.type, p.name, id: p.id);
|
||||
|
|
|
@ -1225,10 +1225,8 @@ void main() {
|
|||
assertTestChangeResult(expectedCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all conditions are OK and the result of applying the change
|
||||
* to [testUnit] is [expectedCode].
|
||||
*/
|
||||
/// Checks that all conditions are OK and the result of applying the change
|
||||
/// to [testUnit] is [expectedCode].
|
||||
Future<void> _assertSuccessfulRefactoring(String expectedCode) async {
|
||||
await assertRefactoringConditionsOK();
|
||||
await _assertRefactoringChange(expectedCode);
|
||||
|
@ -1246,10 +1244,8 @@ void main() {
|
|||
_createRefactoring(offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new refactoring in [refactoring] at the offset of the given
|
||||
* [search] pattern.
|
||||
*/
|
||||
/// Creates a new refactoring in [refactoring] at the offset of the given
|
||||
/// [search] pattern.
|
||||
void _createRefactoringForStringOffset(String search) {
|
||||
int offset = findOffset(search);
|
||||
_createRefactoring(offset, 0);
|
||||
|
|
|
@ -436,10 +436,7 @@ main() {
|
|||
''');
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* https://code.google.com/p/dart/issues/detail?id=18587
|
||||
*/
|
||||
/// https://code.google.com/p/dart/issues/detail?id=18587
|
||||
Future<void> test_OK_keepNextCommentedLine() async {
|
||||
await indexTestUnit('''
|
||||
main() {
|
||||
|
|
|
@ -445,9 +445,7 @@ part of 'a.dart';
|
|||
expectedMessage: expectedMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all conditions are OK.
|
||||
*/
|
||||
/// Checks that all conditions are OK.
|
||||
Future _assertSuccessfulRefactoring() async {
|
||||
await assertRefactoringConditionsOK();
|
||||
refactoringChange = await refactoring.createChange();
|
||||
|
|
|
@ -647,11 +647,9 @@ void main() {
|
|||
offset: testCode.indexOf("test('test2_2'"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Code like this caused NPE in the past.
|
||||
*
|
||||
* https://code.google.com/p/dart/issues/detail?id=21373
|
||||
*/
|
||||
/// Code like this caused NPE in the past.
|
||||
///
|
||||
/// https://code.google.com/p/dart/issues/detail?id=21373
|
||||
Future<void> test_invalidGetterInConstructor() async {
|
||||
Outline outline = await _computeOutline('''
|
||||
class A {
|
||||
|
@ -665,11 +663,9 @@ class A {
|
|||
expect(outline, isNotNull);
|
||||
}
|
||||
|
||||
/**
|
||||
* Code like this caused Dart2 failure in the past.
|
||||
*
|
||||
* https://github.com/dart-lang/sdk/issues/33228
|
||||
*/
|
||||
/// Code like this caused Dart2 failure in the past.
|
||||
///
|
||||
/// https://github.com/dart-lang/sdk/issues/33228
|
||||
Future<void> test_invocation_ofParameter() async {
|
||||
Outline outline = await _computeOutline('''
|
||||
main(p()) {
|
||||
|
|
|
@ -687,18 +687,14 @@ class PluginSessionTest with ResourceProviderMixin {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class designed to be used as a superclass for test classes that define
|
||||
* tests that require plugins to be created on disk.
|
||||
*/
|
||||
/// A class designed to be used as a superclass for test classes that define
|
||||
/// tests that require plugins to be created on disk.
|
||||
abstract class PluginTestSupport {
|
||||
PhysicalResourceProvider resourceProvider;
|
||||
TestNotificationManager notificationManager;
|
||||
|
||||
/**
|
||||
* The content to be used for the '.packages' file, or `null` if the content
|
||||
* has not yet been computed.
|
||||
*/
|
||||
/// The content to be used for the '.packages' file, or `null` if the content
|
||||
/// has not yet been computed.
|
||||
String _packagesFileContent;
|
||||
|
||||
void setUp() {
|
||||
|
@ -706,22 +702,21 @@ abstract class PluginTestSupport {
|
|||
notificationManager = TestNotificationManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a directory structure representing a plugin on disk, run the given
|
||||
* [test] function, and then remove the directory. The directory will have the
|
||||
* following structure:
|
||||
* ```
|
||||
* pluginDirectory
|
||||
* .packages
|
||||
* bin
|
||||
* plugin.dart
|
||||
* ```
|
||||
* The name of the plugin directory will be the [pluginName], if one is
|
||||
* provided (in order to allow more than one plugin to be created by a single
|
||||
* test). The 'plugin.dart' file will contain the given [content], or default
|
||||
* content that implements a minimal plugin if the contents are not given. The
|
||||
* [test] function will be passed the path of the directory that was created.
|
||||
*/
|
||||
/// Create a directory structure representing a plugin on disk, run the given
|
||||
/// [test] function, and then remove the directory. The directory will have
|
||||
/// the following structure:
|
||||
/// ```
|
||||
/// pluginDirectory
|
||||
/// .packages
|
||||
/// bin
|
||||
/// plugin.dart
|
||||
/// ```
|
||||
/// The name of the plugin directory will be the [pluginName], if one is
|
||||
/// provided (in order to allow more than one plugin to be created by a single
|
||||
/// test). The 'plugin.dart' file will contain the given [content], or default
|
||||
/// content that implements a minimal plugin if the contents are not given.
|
||||
/// The [test] function will be passed the path of the directory that was
|
||||
/// created.
|
||||
Future<void> withPlugin(
|
||||
{String content,
|
||||
String pluginName,
|
||||
|
@ -754,22 +749,21 @@ abstract class PluginTestSupport {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a directory structure representing a plugin on disk, run the given
|
||||
* [test] function, and then remove the directory. The directory will have the
|
||||
* following structure:
|
||||
* ```
|
||||
* pluginDirectory
|
||||
* pubspec.yaml
|
||||
* bin
|
||||
* plugin.dart
|
||||
* ```
|
||||
* The name of the plugin directory will be the [pluginName], if one is
|
||||
* provided (in order to allow more than one plugin to be created by a single
|
||||
* test). The 'plugin.dart' file will contain the given [content], or default
|
||||
* content that implements a minimal plugin if the contents are not given. The
|
||||
* [test] function will be passed the path of the directory that was created.
|
||||
*/
|
||||
/// Create a directory structure representing a plugin on disk, run the given
|
||||
/// [test] function, and then remove the directory. The directory will have
|
||||
/// the following structure:
|
||||
/// ```
|
||||
/// pluginDirectory
|
||||
/// pubspec.yaml
|
||||
/// bin
|
||||
/// plugin.dart
|
||||
/// ```
|
||||
/// The name of the plugin directory will be the [pluginName], if one is
|
||||
/// provided (in order to allow more than one plugin to be created by a single
|
||||
/// test). The 'plugin.dart' file will contain the given [content], or default
|
||||
/// content that implements a minimal plugin if the contents are not given.
|
||||
/// The [test] function will be passed the path of the directory that was
|
||||
/// created.
|
||||
Future<void> withPubspecPlugin(
|
||||
{String content,
|
||||
String pluginName,
|
||||
|
@ -802,10 +796,8 @@ abstract class PluginTestSupport {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the [sdkPackageMap] into a plugin-specific map by applying the
|
||||
* given relative path [delta] to each line.
|
||||
*/
|
||||
/// Convert the [sdkPackageMap] into a plugin-specific map by applying the
|
||||
/// given relative path [delta] to each line.
|
||||
String _convertPackageMap(String sdkDirPath, List<String> sdkPackageMap) {
|
||||
StringBuffer buffer = StringBuffer();
|
||||
for (String line in sdkPackageMap) {
|
||||
|
@ -824,10 +816,8 @@ abstract class PluginTestSupport {
|
|||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default content of the plugin. This is a minimal plugin that will only
|
||||
* respond correctly to version checks and to shutdown requests.
|
||||
*/
|
||||
/// The default content of the plugin. This is a minimal plugin that will only
|
||||
/// respond correctly to version checks and to shutdown requests.
|
||||
String _defaultPluginContent() {
|
||||
return r'''
|
||||
import 'dart:async';
|
||||
|
@ -871,9 +861,7 @@ class MinimalPlugin extends ServerPlugin {
|
|||
''';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the content to be used for the '.packages' file.
|
||||
*/
|
||||
/// Return the content to be used for the '.packages' file.
|
||||
String _getPackagesFileContent() {
|
||||
if (_packagesFileContent == null) {
|
||||
io.File sdkPackagesFile = io.File(_sdkPackagesPath());
|
||||
|
@ -884,9 +872,7 @@ class MinimalPlugin extends ServerPlugin {
|
|||
return _packagesFileContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the content to be used for the 'pubspec.yaml' file.
|
||||
*/
|
||||
/// Return the content to be used for the 'pubspec.yaml' file.
|
||||
String _getPubspecFileContent() {
|
||||
return '''
|
||||
name: 'test'
|
||||
|
@ -896,9 +882,7 @@ dependencies:
|
|||
''';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path to the '.packages' file in the root of the SDK checkout.
|
||||
*/
|
||||
/// Return the path to the '.packages' file in the root of the SDK checkout.
|
||||
String _sdkPackagesPath() {
|
||||
String packagesPath = io.Platform.script.toFilePath();
|
||||
while (packagesPath.isNotEmpty &&
|
||||
|
|
|
@ -62,10 +62,8 @@ class ProtocolTestUtilities {
|
|||
'bz',
|
||||
];
|
||||
|
||||
/**
|
||||
* On return, increment [stringIndex] by 3 (or 4 if no [file] name is
|
||||
* provided) and [intIndex] by 4.
|
||||
*/
|
||||
/// On return, increment [stringIndex] by 3 (or 4 if no [file] name is
|
||||
/// provided) and [intIndex] by 4.
|
||||
AnalysisError analysisError(int stringIndex, int intIndex, {String file}) {
|
||||
return AnalysisError(
|
||||
AnalysisErrorSeverity.ERROR,
|
||||
|
@ -77,9 +75,7 @@ class ProtocolTestUtilities {
|
|||
hasFix: true);
|
||||
}
|
||||
|
||||
/**
|
||||
* On return, increment [stringIndex] by 5 and [intIndex] by 5.
|
||||
*/
|
||||
/// On return, increment [stringIndex] by 5 and [intIndex] by 5.
|
||||
Element element(int stringIndex, int intIndex, {ElementKind kind}) =>
|
||||
Element(kind ?? ElementKind.CLASS, strings[stringIndex++], intIndex++,
|
||||
location: Location(fileName(stringIndex++), intIndex++, intIndex++,
|
||||
|
@ -96,9 +92,7 @@ class ProtocolTestUtilities {
|
|||
HighlightRegion highlightRegion(int offset, int length) =>
|
||||
HighlightRegion(HighlightRegionType.FIELD, offset, length);
|
||||
|
||||
/**
|
||||
* On return, increment [stringIndex] by 1 and [intIndex] by 4.
|
||||
*/
|
||||
/// On return, increment [stringIndex] by 1 and [intIndex] by 4.
|
||||
Location location(int stringIndex, int intIndex, {String file}) => Location(
|
||||
file ?? fileName(stringIndex),
|
||||
intIndex++,
|
||||
|
@ -106,18 +100,14 @@ class ProtocolTestUtilities {
|
|||
intIndex++,
|
||||
intIndex++);
|
||||
|
||||
/**
|
||||
* On return, increment [stringIndex] by 5 and [intIndex] by 7.
|
||||
*/
|
||||
/// On return, increment [stringIndex] by 5 and [intIndex] by 7.
|
||||
Occurrences occurrences(int stringIndex, int intIndex) {
|
||||
Element referencedElement = element(stringIndex, intIndex);
|
||||
return Occurrences(referencedElement, <int>[intIndex + 5, intIndex + 6],
|
||||
referencedElement.name.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* On return, increment [stringIndex] by 10 and [intIndex] by 14.
|
||||
*/
|
||||
/// On return, increment [stringIndex] by 10 and [intIndex] by 14.
|
||||
Outline outline(int stringIndex, int intIndex) => Outline(
|
||||
element(stringIndex, intIndex),
|
||||
intIndex + 5,
|
||||
|
@ -134,10 +124,8 @@ class ProtocolTestUtilities {
|
|||
intIndex + 13)
|
||||
]);
|
||||
|
||||
/**
|
||||
* On return, increment [stringIndex] by 2 (or 3 if no [file] name is
|
||||
* provided) and [intIndex] by 4.
|
||||
*/
|
||||
/// On return, increment [stringIndex] by 2 (or 3 if no [file] name is
|
||||
/// provided) and [intIndex] by 4.
|
||||
plugin.AnalysisNavigationParams pluginNavigationParams(
|
||||
int stringIndex, int intIndex, {String file}) =>
|
||||
plugin.AnalysisNavigationParams(
|
||||
|
@ -151,19 +139,15 @@ class ProtocolTestUtilities {
|
|||
strings[stringIndex++]
|
||||
]);
|
||||
|
||||
/**
|
||||
* On return, increment [stringIndex] by 2 and [intIndex] by 4.
|
||||
*/
|
||||
/// On return, increment [stringIndex] by 2 and [intIndex] by 4.
|
||||
RefactoringProblem refactoringProblem(int stringIndex, int intIndex) {
|
||||
return RefactoringProblem(
|
||||
RefactoringProblemSeverity.FATAL, strings[stringIndex++],
|
||||
location: location(stringIndex, intIndex));
|
||||
}
|
||||
|
||||
/**
|
||||
* On return, increment [stringIndex] by 2 (or 3 if no [file] name is
|
||||
* provided) and [intIndex] by 4.
|
||||
*/
|
||||
/// On return, increment [stringIndex] by 2 (or 3 if no [file] name is
|
||||
/// provided) and [intIndex] by 4.
|
||||
server.AnalysisNavigationParams serverNavigationParams(
|
||||
int stringIndex, int intIndex, {String file}) =>
|
||||
server.AnalysisNavigationParams(
|
||||
|
@ -177,9 +161,7 @@ class ProtocolTestUtilities {
|
|||
strings[stringIndex++]
|
||||
]);
|
||||
|
||||
/**
|
||||
* On return, increment [stringIndex] by 6 and [intIndex] by 6.
|
||||
*/
|
||||
/// On return, increment [stringIndex] by 6 and [intIndex] by 6.
|
||||
SourceChange sourceChange(int stringIndex, int intIndex) =>
|
||||
SourceChange(strings[stringIndex++],
|
||||
edits: <SourceFileEdit>[
|
||||
|
|
|
@ -8,9 +8,7 @@ import 'package:args/args.dart';
|
|||
|
||||
import 'completion_runner.dart';
|
||||
|
||||
/**
|
||||
* The main entry point for the code completion stress test.
|
||||
*/
|
||||
/// The main entry point for the code completion stress test.
|
||||
void main(List<String> args) async {
|
||||
ArgParser parser = createArgParser();
|
||||
ArgResults result = parser.parse(args);
|
||||
|
@ -29,9 +27,7 @@ void main(List<String> args) async {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a parser that can be used to parse the command-line arguments.
|
||||
*/
|
||||
/// Create a parser that can be used to parse the command-line arguments.
|
||||
ArgParser createArgParser() {
|
||||
ArgParser parser = ArgParser();
|
||||
parser.addFlag(
|
||||
|
@ -64,9 +60,7 @@ ArgParser createArgParser() {
|
|||
return parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print usage information for this tool.
|
||||
*/
|
||||
/// Print usage information for this tool.
|
||||
void printUsage(ArgParser parser, {String error}) {
|
||||
if (error != null) {
|
||||
print(error);
|
||||
|
@ -81,10 +75,8 @@ void printUsage(ArgParser parser, {String error}) {
|
|||
print(parser.usage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if the command-line arguments (represented by the [result] and
|
||||
* parsed by the [parser]) are valid.
|
||||
*/
|
||||
/// Return `true` if the command-line arguments (represented by the [result] and
|
||||
/// parsed by the [parser]) are valid.
|
||||
bool validArguments(ArgParser parser, ArgResults result) {
|
||||
if (result.wasParsed('help')) {
|
||||
printUsage(parser);
|
||||
|
|
|
@ -19,46 +19,30 @@ import 'package:analyzer/source/line_info.dart';
|
|||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer_plugin/protocol/protocol_common.dart';
|
||||
|
||||
/**
|
||||
* A runner that can request code completion at the location of each identifier
|
||||
* in a Dart file.
|
||||
*/
|
||||
/// A runner that can request code completion at the location of each identifier
|
||||
/// in a Dart file.
|
||||
class CompletionRunner {
|
||||
/**
|
||||
* The sink to which output is to be written.
|
||||
*/
|
||||
/// The sink to which output is to be written.
|
||||
final StringSink output;
|
||||
|
||||
/**
|
||||
* A flag indicating whether to produce output about missing suggestions.
|
||||
*/
|
||||
/// A flag indicating whether to produce output about missing suggestions.
|
||||
final bool printMissing;
|
||||
|
||||
/**
|
||||
* A flag indicating whether to produce output about the quality of the sort
|
||||
* order.
|
||||
*/
|
||||
/// A flag indicating whether to produce output about the quality of the sort
|
||||
/// order.
|
||||
final bool printQuality;
|
||||
|
||||
/**
|
||||
* A flag indicating whether to produce timing information.
|
||||
*/
|
||||
/// A flag indicating whether to produce timing information.
|
||||
final bool timing;
|
||||
|
||||
/**
|
||||
* A flag indicating whether to produce verbose output.
|
||||
*/
|
||||
/// A flag indicating whether to produce verbose output.
|
||||
final bool verbose;
|
||||
|
||||
/**
|
||||
* A flag indicating whether we should delete each identifier before
|
||||
* attempting to complete at that offset.
|
||||
*/
|
||||
/// A flag indicating whether we should delete each identifier before
|
||||
/// attempting to complete at that offset.
|
||||
bool deleteBeforeCompletion = false;
|
||||
|
||||
/**
|
||||
* Initialize a newly created completion runner.
|
||||
*/
|
||||
/// Initialize a newly created completion runner.
|
||||
CompletionRunner(
|
||||
{StringSink output,
|
||||
bool printMissing,
|
||||
|
@ -71,10 +55,8 @@ class CompletionRunner {
|
|||
timing = timing ?? false,
|
||||
verbose = verbose ?? false;
|
||||
|
||||
/**
|
||||
* Test the completion engine at the locations of each of the identifiers in
|
||||
* each of the files in the given [analysisRoot].
|
||||
*/
|
||||
/// Test the completion engine at the locations of each of the identifiers in
|
||||
/// each of the files in the given [analysisRoot].
|
||||
Future<void> runAll(String analysisRoot) async {
|
||||
OverlayResourceProvider resourceProvider =
|
||||
OverlayResourceProvider(PhysicalResourceProvider.INSTANCE);
|
||||
|
@ -228,20 +210,16 @@ class CompletionRunner {
|
|||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list containing information about the identifiers in the given
|
||||
* compilation [unit].
|
||||
*/
|
||||
/// Return a list containing information about the identifiers in the given
|
||||
/// compilation [unit].
|
||||
List<SimpleIdentifier> _identifiersIn(CompilationUnit unit) {
|
||||
IdentifierCollector visitor = IdentifierCollector();
|
||||
unit.accept(visitor);
|
||||
return visitor.identifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given list of [suggestions] includes a suggestion for the given
|
||||
* [identifier], return the index of the suggestion. Otherwise, return `-1`.
|
||||
*/
|
||||
/// If the given list of [suggestions] includes a suggestion for the given
|
||||
/// [identifier], return the index of the suggestion. Otherwise, return `-1`.
|
||||
int _indexOf(List<CompletionSuggestion> suggestions, String identifier) {
|
||||
for (int i = 0; i < suggestions.length; i++) {
|
||||
if (suggestions[i].completion == identifier) {
|
||||
|
@ -251,18 +229,14 @@ class CompletionRunner {
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if the given [identifier] is being used as the name of a
|
||||
* named expression.
|
||||
*/
|
||||
/// Return `true` if the given [identifier] is being used as the name of a
|
||||
/// named expression.
|
||||
bool _isNamedExpressionName(SimpleIdentifier identifier) {
|
||||
AstNode parent = identifier.parent;
|
||||
return parent is NamedExpression && parent.name.label == identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print information about the given [suggestions].
|
||||
*/
|
||||
/// Print information about the given [suggestions].
|
||||
void _printSuggestions(List<CompletionSuggestion> suggestions) {
|
||||
if (suggestions.isEmpty) {
|
||||
output.writeln(' No suggestions');
|
||||
|
@ -280,13 +254,9 @@ class CompletionRunner {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A visitor that will collect simple identifiers in the AST being visited.
|
||||
*/
|
||||
/// A visitor that will collect simple identifiers in the AST being visited.
|
||||
class IdentifierCollector extends RecursiveAstVisitor<void> {
|
||||
/**
|
||||
* The simple identifiers that were collected.
|
||||
*/
|
||||
/// The simple identifiers that were collected.
|
||||
final List<SimpleIdentifier> identifiers = <SimpleIdentifier>[];
|
||||
|
||||
@override
|
||||
|
|
|
@ -2,29 +2,19 @@
|
|||
// 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.
|
||||
|
||||
/**
|
||||
* Operations to be performed during the simulation.
|
||||
*/
|
||||
/// Operations to be performed during the simulation.
|
||||
import '../utilities/server.dart';
|
||||
|
||||
/**
|
||||
* An operation that will send an 'analysis.updateContent' request.
|
||||
*/
|
||||
/// An operation that will send an 'analysis.updateContent' request.
|
||||
class Analysis_UpdateContent extends ServerOperation {
|
||||
/**
|
||||
* The path of the file whose content is being updated.
|
||||
*/
|
||||
/// The path of the file whose content is being updated.
|
||||
final String filePath;
|
||||
|
||||
/**
|
||||
* The overlay used to update the content.
|
||||
*/
|
||||
/// The overlay used to update the content.
|
||||
final dynamic overlay;
|
||||
|
||||
/**
|
||||
* Initialize an operation to send an 'analysis.updateContent' request with
|
||||
* the given [filePath] and [overlay] as parameters.
|
||||
*/
|
||||
/// Initialize an operation to send an 'analysis.updateContent' request with
|
||||
/// the given [filePath] and [overlay] as parameters.
|
||||
Analysis_UpdateContent(this.filePath, this.overlay);
|
||||
|
||||
@override
|
||||
|
@ -43,24 +33,16 @@ class Analysis_UpdateContent extends ServerOperation {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operation that will send a 'completion.getSuggestions' request.
|
||||
*/
|
||||
/// An operation that will send a 'completion.getSuggestions' request.
|
||||
class Completion_GetSuggestions extends ServerOperation {
|
||||
/**
|
||||
* The path of the file in which completions are being requested.
|
||||
*/
|
||||
/// The path of the file in which completions are being requested.
|
||||
final String filePath;
|
||||
|
||||
/**
|
||||
* The offset at which completions are being requested.
|
||||
*/
|
||||
/// The offset at which completions are being requested.
|
||||
final int offset;
|
||||
|
||||
/**
|
||||
* Initialize an operation to send a 'completion.getSuggestions' request with
|
||||
* the given [filePath] and [offset] as parameters.
|
||||
*/
|
||||
/// Initialize an operation to send a 'completion.getSuggestions' request with
|
||||
/// the given [filePath] and [offset] as parameters.
|
||||
Completion_GetSuggestions(this.filePath, this.offset);
|
||||
|
||||
@override
|
||||
|
@ -69,12 +51,8 @@ class Completion_GetSuggestions extends ServerOperation {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operation to be performed during the simulation.
|
||||
*/
|
||||
/// An operation to be performed during the simulation.
|
||||
abstract class ServerOperation {
|
||||
/**
|
||||
* Perform this operation by communicating with the given [server].
|
||||
*/
|
||||
/// Perform this operation by communicating with the given [server].
|
||||
void perform(Server server);
|
||||
}
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
// 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.
|
||||
|
||||
/**
|
||||
* A stress test for the analysis server.
|
||||
*/
|
||||
/// A stress test for the analysis server.
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math' as math;
|
||||
|
@ -27,122 +25,80 @@ import '../utilities/logger.dart';
|
|||
import '../utilities/server.dart';
|
||||
import 'operation.dart';
|
||||
|
||||
/**
|
||||
* Run the simulation based on the given command-line [arguments].
|
||||
*/
|
||||
/// Run the simulation based on the given command-line [arguments].
|
||||
Future<void> main(List<String> arguments) async {
|
||||
Driver driver = Driver();
|
||||
await driver.run(arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* The driver class that runs the simulation.
|
||||
*/
|
||||
/// The driver class that runs the simulation.
|
||||
class Driver {
|
||||
/**
|
||||
* The value of the [OVERLAY_STYLE_OPTION_NAME] indicating that modifications
|
||||
* to a file should be represented by an add overlay, followed by zero or more
|
||||
* change overlays, followed by a remove overlay.
|
||||
*/
|
||||
/// The value of the [OVERLAY_STYLE_OPTION_NAME] indicating that modifications
|
||||
/// to a file should be represented by an add overlay, followed by zero or
|
||||
/// more change overlays, followed by a remove overlay.
|
||||
static String CHANGE_OVERLAY_STYLE = 'change';
|
||||
|
||||
/**
|
||||
* The name of the command-line flag that will print help text.
|
||||
*/
|
||||
/// The name of the command-line flag that will print help text.
|
||||
static String HELP_FLAG_NAME = 'help';
|
||||
|
||||
/**
|
||||
* The value of the [OVERLAY_STYLE_OPTION_NAME] indicating that modifications
|
||||
* to a file should be represented by an add overlay, followed by zero or more
|
||||
* additional add overlays, followed by a remove overlay.
|
||||
*/
|
||||
/// The value of the [OVERLAY_STYLE_OPTION_NAME] indicating that modifications
|
||||
/// to a file should be represented by an add overlay, followed by zero or
|
||||
/// more additional add overlays, followed by a remove overlay.
|
||||
static String MULTIPLE_ADD_OVERLAY_STYLE = 'multipleAdd';
|
||||
|
||||
/**
|
||||
* The name of the command-line option used to specify the style of
|
||||
* interaction to use when making `analysis.updateContent` requests.
|
||||
*/
|
||||
/// The name of the command-line option used to specify the style of
|
||||
/// interaction to use when making `analysis.updateContent` requests.
|
||||
static String OVERLAY_STYLE_OPTION_NAME = 'overlay-style';
|
||||
|
||||
/**
|
||||
* The name of the pubspec file.
|
||||
*/
|
||||
/// The name of the pubspec file.
|
||||
static const String PUBSPEC_FILE_NAME = 'pubspec.yaml';
|
||||
|
||||
/**
|
||||
* The name of the branch used to clean-up after making temporary changes.
|
||||
*/
|
||||
/// The name of the branch used to clean-up after making temporary changes.
|
||||
static const String TEMP_BRANCH_NAME = 'temp';
|
||||
|
||||
/**
|
||||
* The name of the command-line flag that will cause verbose output to be
|
||||
* produced.
|
||||
*/
|
||||
/// The name of the command-line flag that will cause verbose output to be
|
||||
/// produced.
|
||||
static String VERBOSE_FLAG_NAME = 'verbose';
|
||||
|
||||
/**
|
||||
* The style of interaction to use for analysis.updateContent requests.
|
||||
*/
|
||||
/// The style of interaction to use for analysis.updateContent requests.
|
||||
OverlayStyle overlayStyle;
|
||||
|
||||
/**
|
||||
* The absolute path of the repository.
|
||||
*/
|
||||
/// The absolute path of the repository.
|
||||
String repositoryPath;
|
||||
|
||||
/**
|
||||
* The absolute paths to the analysis roots.
|
||||
*/
|
||||
/// The absolute paths to the analysis roots.
|
||||
List<String> analysisRoots;
|
||||
|
||||
/**
|
||||
* The git repository.
|
||||
*/
|
||||
/// The git repository.
|
||||
GitRepository repository;
|
||||
|
||||
/**
|
||||
* The connection to the analysis server.
|
||||
*/
|
||||
/// The connection to the analysis server.
|
||||
Server server;
|
||||
|
||||
/**
|
||||
* A list of the glob patterns used to identify the files being analyzed by
|
||||
* the server.
|
||||
*/
|
||||
/// A list of the glob patterns used to identify the files being analyzed by
|
||||
/// the server.
|
||||
List<Glob> fileGlobs;
|
||||
|
||||
/**
|
||||
* An object gathering statistics about the simulation.
|
||||
*/
|
||||
/// An object gathering statistics about the simulation.
|
||||
Statistics statistics;
|
||||
|
||||
/**
|
||||
* A flag indicating whether verbose output should be provided.
|
||||
*/
|
||||
/// A flag indicating whether verbose output should be provided.
|
||||
bool verbose = false;
|
||||
|
||||
/**
|
||||
* The logger to which verbose logging data will be written.
|
||||
*/
|
||||
/// The logger to which verbose logging data will be written.
|
||||
Logger logger;
|
||||
|
||||
/**
|
||||
* Initialize a newly created driver.
|
||||
*/
|
||||
/// Initialize a newly created driver.
|
||||
Driver() {
|
||||
statistics = Statistics(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the output from the server to be read and processed.
|
||||
*/
|
||||
/// Allow the output from the server to be read and processed.
|
||||
Future<void> readServerOutput() async {
|
||||
await Future.delayed(Duration(milliseconds: 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the simulation based on the given command-line arguments ([args]).
|
||||
*/
|
||||
/// Run the simulation based on the given command-line arguments ([args]).
|
||||
Future<void> run(List<String> args) async {
|
||||
//
|
||||
// Process the command-line arguments.
|
||||
|
@ -176,10 +132,8 @@ class Driver {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a parser that can be used to parse the command-line
|
||||
* arguments.
|
||||
*/
|
||||
/// Create and return a parser that can be used to parse the command-line
|
||||
/// arguments.
|
||||
ArgParser _createArgParser() {
|
||||
ArgParser parser = ArgParser();
|
||||
parser.addFlag(HELP_FLAG_NAME,
|
||||
|
@ -204,9 +158,7 @@ class Driver {
|
|||
return parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add source edits to the given [fileEdit] based on the given [blobDiff].
|
||||
*/
|
||||
/// Add source edits to the given [fileEdit] based on the given [blobDiff].
|
||||
void _createSourceEdits(FileEdit fileEdit, BlobDiff blobDiff) {
|
||||
LineInfo info = fileEdit.lineInfo;
|
||||
for (DiffHunk hunk in blobDiff.hunks) {
|
||||
|
@ -245,10 +197,8 @@ class Driver {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute paths of all of the pubspec files in all of the
|
||||
* analysis roots.
|
||||
*/
|
||||
/// Return the absolute paths of all of the pubspec files in all of the
|
||||
/// analysis roots.
|
||||
Iterable<String> _findPubspecsInAnalysisRoots() {
|
||||
List<String> pubspecFiles = <String>[];
|
||||
for (String directoryPath in analysisRoots) {
|
||||
|
@ -265,10 +215,8 @@ class Driver {
|
|||
return pubspecFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of offsets into the given [text] that represent good places
|
||||
* to break the text when building edits.
|
||||
*/
|
||||
/// Return a list of offsets into the given [text] that represent good places
|
||||
/// to break the text when building edits.
|
||||
List<int> _getBreakOffsets(String text) {
|
||||
List<int> breakOffsets = <int>[];
|
||||
Scanner scanner = Scanner(null, CharSequenceReader(text),
|
||||
|
@ -290,9 +238,7 @@ class Driver {
|
|||
return breakOffsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the given [lines] into a single string.
|
||||
*/
|
||||
/// Join the given [lines] into a single string.
|
||||
String _join(List<String> lines) {
|
||||
StringBuffer buffer = StringBuffer();
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
|
@ -301,10 +247,8 @@ class Driver {
|
|||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the command-line [arguments]. Return `true` if the simulation
|
||||
* should be run.
|
||||
*/
|
||||
/// Process the command-line [arguments]. Return `true` if the simulation
|
||||
/// should be run.
|
||||
bool _processCommandLine(List<String> args) {
|
||||
ArgParser parser = _createArgParser();
|
||||
ArgResults results;
|
||||
|
@ -355,9 +299,7 @@ class Driver {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replay the changes in each commit.
|
||||
*/
|
||||
/// Replay the changes in each commit.
|
||||
Future<void> _replayChanges() async {
|
||||
//
|
||||
// Get the revision history of the repo.
|
||||
|
@ -424,10 +366,8 @@ class Driver {
|
|||
stdout.writeln();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replay the changes between two commits, as represented by the given
|
||||
* [commitDelta].
|
||||
*/
|
||||
/// Replay the changes between two commits, as represented by the given
|
||||
/// [commitDelta].
|
||||
Future<void> _replayDiff(CommitDelta commitDelta) async {
|
||||
List<FileEdit> editList = <FileEdit>[];
|
||||
for (DiffRecord record in commitDelta.diffRecords) {
|
||||
|
@ -460,9 +400,7 @@ class Driver {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run `pub` on the pubspec with the given [filePath].
|
||||
*/
|
||||
/// Run `pub` on the pubspec with the given [filePath].
|
||||
void _runPub(String filePath) {
|
||||
String directoryPath = path.dirname(filePath);
|
||||
if (Directory(directoryPath).existsSync()) {
|
||||
|
@ -472,9 +410,7 @@ class Driver {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the simulation by starting up a server and sending it requests.
|
||||
*/
|
||||
/// Run the simulation by starting up a server and sending it requests.
|
||||
Future<void> _runSimulation() async {
|
||||
server = Server(logger: logger);
|
||||
Stopwatch stopwatch = Stopwatch();
|
||||
|
@ -503,9 +439,7 @@ class Driver {
|
|||
stopwatch.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display usage information, preceded by the [errorMessage] if one is given.
|
||||
*/
|
||||
/// Display usage information, preceded by the [errorMessage] if one is given.
|
||||
void _showUsage(ArgParser parser, [String errorMessage]) {
|
||||
if (errorMessage != null) {
|
||||
stderr.writeln(errorMessage);
|
||||
|
@ -531,45 +465,29 @@ OPTIONS:''');
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A representation of the edits to be applied to a single file.
|
||||
*/
|
||||
/// A representation of the edits to be applied to a single file.
|
||||
class FileEdit {
|
||||
/**
|
||||
* The style of interaction to use for analysis.updateContent requests.
|
||||
*/
|
||||
/// The style of interaction to use for analysis.updateContent requests.
|
||||
OverlayStyle overlayStyle;
|
||||
|
||||
/**
|
||||
* The absolute path of the file to be edited.
|
||||
*/
|
||||
/// The absolute path of the file to be edited.
|
||||
String filePath;
|
||||
|
||||
/**
|
||||
* The content of the file before any edits have been applied.
|
||||
*/
|
||||
/// The content of the file before any edits have been applied.
|
||||
String content;
|
||||
|
||||
/**
|
||||
* The line info for the file before any edits have been applied.
|
||||
*/
|
||||
/// The line info for the file before any edits have been applied.
|
||||
LineInfo lineInfo;
|
||||
|
||||
/**
|
||||
* The lists of source edits, one list for each hunk being edited.
|
||||
*/
|
||||
/// The lists of source edits, one list for each hunk being edited.
|
||||
List<List<SourceEdit>> editLists = <List<SourceEdit>>[];
|
||||
|
||||
/**
|
||||
* The current content of the file. This field is only used if the overlay
|
||||
* style is [OverlayStyle.multipleAdd].
|
||||
*/
|
||||
/// The current content of the file. This field is only used if the overlay
|
||||
/// style is [OverlayStyle.multipleAdd].
|
||||
String currentContent;
|
||||
|
||||
/**
|
||||
* Initialize a collection of edits to be associated with the file at the
|
||||
* given [filePath].
|
||||
*/
|
||||
/// Initialize a collection of edits to be associated with the file at the
|
||||
/// given [filePath].
|
||||
FileEdit(this.overlayStyle, DiffRecord record) {
|
||||
filePath = record.srcPath;
|
||||
if (record.isAddition) {
|
||||
|
@ -584,17 +502,13 @@ class FileEdit {
|
|||
currentContent = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a list of source edits that, taken together, transform a single hunk in
|
||||
* the file.
|
||||
*/
|
||||
/// Add a list of source edits that, taken together, transform a single hunk
|
||||
/// in the file.
|
||||
void addSourceEdits(List<SourceEdit> sourceEdits) {
|
||||
editLists.add(sourceEdits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of operations to be sent to the server.
|
||||
*/
|
||||
/// Return a list of operations to be sent to the server.
|
||||
List<ServerOperation> getOperations() {
|
||||
List<ServerOperation> operations = <ServerOperation>[];
|
||||
void addUpdateContent(var overlay) {
|
||||
|
@ -626,49 +540,32 @@ class FileEdit {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The possible styles of interaction to use for analysis.updateContent requests.
|
||||
*/
|
||||
/// The possible styles of interaction to use for analysis.updateContent
|
||||
/// requests.
|
||||
enum OverlayStyle { change, multipleAdd }
|
||||
|
||||
/**
|
||||
* A set of statistics related to the execution of the simulation.
|
||||
*/
|
||||
/// A set of statistics related to the execution of the simulation.
|
||||
class Statistics {
|
||||
/**
|
||||
* The driver driving the simulation.
|
||||
*/
|
||||
/// The driver driving the simulation.
|
||||
final Driver driver;
|
||||
|
||||
/**
|
||||
* The stopwatch being used to time the simulation.
|
||||
*/
|
||||
/// The stopwatch being used to time the simulation.
|
||||
Stopwatch stopwatch;
|
||||
|
||||
/**
|
||||
* The total number of commits in the repository.
|
||||
*/
|
||||
/// The total number of commits in the repository.
|
||||
int commitCount;
|
||||
|
||||
/**
|
||||
* The number of commits in the repository that touched one of the files in
|
||||
* one of the analysis roots.
|
||||
*/
|
||||
/// The number of commits in the repository that touched one of the files in
|
||||
/// one of the analysis roots.
|
||||
int commitsWithChangeInRootCount = 0;
|
||||
|
||||
/**
|
||||
* The total number of edits that were applied.
|
||||
*/
|
||||
/// The total number of edits that were applied.
|
||||
int editCount = 0;
|
||||
|
||||
/**
|
||||
* Initialize a newly created set of statistics.
|
||||
*/
|
||||
/// Initialize a newly created set of statistics.
|
||||
Statistics(this.driver);
|
||||
|
||||
/**
|
||||
* Print the statistics to [stdout].
|
||||
*/
|
||||
/// Print the statistics to [stdout].
|
||||
void print() {
|
||||
stdout.write('Replay commits in ');
|
||||
stdout.writeln(driver.repositoryPath);
|
||||
|
@ -684,10 +581,8 @@ class Statistics {
|
|||
stdout.writeln(editCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a textual representation of the given duration, represented in
|
||||
* [milliseconds].
|
||||
*/
|
||||
/// Return a textual representation of the given duration, represented in
|
||||
/// [milliseconds].
|
||||
String _printTime(int milliseconds) {
|
||||
int seconds = milliseconds ~/ 1000;
|
||||
milliseconds -= seconds * 1000;
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
// 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.
|
||||
|
||||
/**
|
||||
* Support for interacting with a git repository.
|
||||
*/
|
||||
/// Support for interacting with a git repository.
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
|
@ -13,43 +11,31 @@ import 'package:path/path.dart' as path;
|
|||
|
||||
import 'logger.dart';
|
||||
|
||||
/**
|
||||
* A representation of the differences between two blobs.
|
||||
*/
|
||||
/// A representation of the differences between two blobs.
|
||||
class BlobDiff {
|
||||
/**
|
||||
* The regular expression used to identify the beginning of a hunk.
|
||||
*/
|
||||
/// The regular expression used to identify the beginning of a hunk.
|
||||
static final RegExp hunkHeaderRegExp =
|
||||
RegExp(r'@@ -([0-9]+)(?:,[0-9]+)? \+([0-9]+)(?:,[0-9]+)? @@');
|
||||
|
||||
/**
|
||||
* A list of the hunks in the diff.
|
||||
*/
|
||||
/// A list of the hunks in the diff.
|
||||
List<DiffHunk> hunks = <DiffHunk>[];
|
||||
|
||||
/**
|
||||
* Initialize a newly created blob diff by parsing the result of the git diff
|
||||
* command (the [input]).
|
||||
*
|
||||
* This is only intended to be invoked from [GitRepository.getBlobDiff].
|
||||
*/
|
||||
/// Initialize a newly created blob diff by parsing the result of the git diff
|
||||
/// command (the [input]).
|
||||
///
|
||||
/// This is only intended to be invoked from [GitRepository.getBlobDiff].
|
||||
BlobDiff._(List<String> input) {
|
||||
_parseInput(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the result of the git diff command (the [input]).
|
||||
*/
|
||||
/// Parse the result of the git diff command (the [input]).
|
||||
void _parseInput(List<String> input) {
|
||||
for (String line in input) {
|
||||
_parseLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single [line] from the result of the git diff command.
|
||||
*/
|
||||
/// Parse a single [line] from the result of the git diff command.
|
||||
void _parseLine(String line) {
|
||||
DiffHunk currentHunk = hunks.isEmpty ? null : hunks.last;
|
||||
if (line.startsWith('@@')) {
|
||||
|
@ -65,71 +51,49 @@ class BlobDiff {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A representation of the differences between two commits.
|
||||
*/
|
||||
/// A representation of the differences between two commits.
|
||||
class CommitDelta {
|
||||
/**
|
||||
* The length (in characters) of a SHA.
|
||||
*/
|
||||
/// The length (in characters) of a SHA.
|
||||
static final int SHA_LENGTH = 40;
|
||||
|
||||
/**
|
||||
* The code-point for a colon (':').
|
||||
*/
|
||||
/// The code-point for a colon (':').
|
||||
static final int COLON = ':'.codeUnitAt(0);
|
||||
|
||||
/**
|
||||
* The code-point for a nul character.
|
||||
*/
|
||||
/// The code-point for a nul character.
|
||||
static final int NUL = 0;
|
||||
|
||||
/**
|
||||
* The code-point for a tab.
|
||||
*/
|
||||
/// The code-point for a tab.
|
||||
static final int TAB = '\t'.codeUnitAt(0);
|
||||
|
||||
/**
|
||||
* The repository from which the commits were taken.
|
||||
*/
|
||||
/// The repository from which the commits were taken.
|
||||
final GitRepository repository;
|
||||
|
||||
/**
|
||||
* The records of the files that were changed.
|
||||
*/
|
||||
/// The records of the files that were changed.
|
||||
final List<DiffRecord> diffRecords = <DiffRecord>[];
|
||||
|
||||
/**
|
||||
* Initialize a newly created representation of the differences between two
|
||||
* commits. The differences are computed by parsing the result of a git diff
|
||||
* command (the [diffResults]).
|
||||
*
|
||||
* This is only intended to be invoked from [GitRepository.getBlobDiff].
|
||||
*/
|
||||
/// Initialize a newly created representation of the differences between two
|
||||
/// commits. The differences are computed by parsing the result of a git diff
|
||||
/// command (the [diffResults]).
|
||||
///
|
||||
/// This is only intended to be invoked from [GitRepository.getBlobDiff].
|
||||
CommitDelta._(this.repository, String diffResults) {
|
||||
_parseInput(diffResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if there are differences.
|
||||
*/
|
||||
/// Return `true` if there are differences.
|
||||
bool get hasDiffs => diffRecords.isNotEmpty;
|
||||
|
||||
/**
|
||||
* Return the absolute paths of all of the files in this commit whose name
|
||||
* matches the given [fileName].
|
||||
*/
|
||||
/// Return the absolute paths of all of the files in this commit whose name
|
||||
/// matches the given [fileName].
|
||||
Iterable<String> filesMatching(String fileName) {
|
||||
return diffRecords
|
||||
.where((DiffRecord record) => record.isFor(fileName))
|
||||
.map((DiffRecord record) => record.srcPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any diffs for files that are either (a) outside the given
|
||||
* [inclusionPaths], or (b) are files that do not match one of the given
|
||||
* [globPatterns].
|
||||
*/
|
||||
/// Remove any diffs for files that are either (a) outside the given
|
||||
/// [inclusionPaths], or (b) are files that do not match one of the given
|
||||
/// [globPatterns].
|
||||
void filterDiffs(List<String> inclusionPaths, List<Glob> globPatterns) {
|
||||
diffRecords.retainWhere((DiffRecord record) {
|
||||
String filePath = record.srcPath ?? record.dstPath;
|
||||
|
@ -146,10 +110,8 @@ class CommitDelta {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index of the first nul character in the given [string] that is
|
||||
* at or after the given [start] index.
|
||||
*/
|
||||
/// Return the index of the first nul character in the given [string] that is
|
||||
/// at or after the given [start] index.
|
||||
int _findEnd(String string, int start) {
|
||||
int length = string.length;
|
||||
int end = start;
|
||||
|
@ -159,17 +121,13 @@ class CommitDelta {
|
|||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the result of converting the given [relativePath] to an absolute
|
||||
* path. The path is assumed to be relative to the root of the repository.
|
||||
*/
|
||||
/// Return the result of converting the given [relativePath] to an absolute
|
||||
/// path. The path is assumed to be relative to the root of the repository.
|
||||
String _makeAbsolute(String relativePath) {
|
||||
return path.join(repository.path, relativePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse all of the diff records in the given [input].
|
||||
*/
|
||||
/// Parse all of the diff records in the given [input].
|
||||
void _parseInput(String input) {
|
||||
int length = input.length;
|
||||
int start = 0;
|
||||
|
@ -178,29 +136,27 @@ class CommitDelta {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single record from the given [input], assuming that the record
|
||||
* starts at the given [startIndex].
|
||||
*
|
||||
* Each record is formatted as a sequence of fields. The fields are, from the
|
||||
* left to the right:
|
||||
*
|
||||
* 1. a colon.
|
||||
* 2. mode for "src"; 000000 if creation or unmerged.
|
||||
* 3. a space.
|
||||
* 4. mode for "dst"; 000000 if deletion or unmerged.
|
||||
* 5. a space.
|
||||
* 6. sha1 for "src"; 0{40} if creation or unmerged.
|
||||
* 7. a space.
|
||||
* 8. sha1 for "dst"; 0{40} if creation, unmerged or "look at work tree".
|
||||
* 9. a space.
|
||||
* 10. status, followed by optional "score" number.
|
||||
* 11. a tab or a NUL when -z option is used.
|
||||
* 12. path for "src"
|
||||
* 13. a tab or a NUL when -z option is used; only exists for C or R.
|
||||
* 14. path for "dst"; only exists for C or R.
|
||||
* 15. an LF or a NUL when -z option is used, to terminate the record.
|
||||
*/
|
||||
/// Parse a single record from the given [input], assuming that the record
|
||||
/// starts at the given [startIndex].
|
||||
///
|
||||
/// Each record is formatted as a sequence of fields. The fields are, from the
|
||||
/// left to the right:
|
||||
///
|
||||
/// 1. a colon.
|
||||
/// 2. mode for "src"; 000000 if creation or unmerged.
|
||||
/// 3. a space.
|
||||
/// 4. mode for "dst"; 000000 if deletion or unmerged.
|
||||
/// 5. a space.
|
||||
/// 6. sha1 for "src"; 0{40} if creation or unmerged.
|
||||
/// 7. a space.
|
||||
/// 8. sha1 for "dst"; 0{40} if creation, unmerged or "look at work tree".
|
||||
/// 9. a space.
|
||||
/// 10. status, followed by optional "score" number.
|
||||
/// 11. a tab or a NUL when -z option is used.
|
||||
/// 12. path for "src"
|
||||
/// 13. a tab or a NUL when -z option is used; only exists for C or R.
|
||||
/// 14. path for "dst"; only exists for C or R.
|
||||
/// 15. an LF or a NUL when -z option is used, to terminate the record.
|
||||
int _parseRecord(String input, int startIndex) {
|
||||
// Skip the first five fields.
|
||||
startIndex += 15;
|
||||
|
@ -231,152 +187,105 @@ class CommitDelta {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Representation of a single diff hunk.
|
||||
*/
|
||||
/// Representation of a single diff hunk.
|
||||
class DiffHunk {
|
||||
/**
|
||||
* The index of the first line that was changed in the src as returned by the
|
||||
* diff command. The diff command numbers lines starting at 1, but it
|
||||
* subtracts 1 from the line number if there are no lines on the source side
|
||||
* of the hunk.
|
||||
*/
|
||||
/// The index of the first line that was changed in the src as returned by the
|
||||
/// diff command. The diff command numbers lines starting at 1, but it
|
||||
/// subtracts 1 from the line number if there are no lines on the source side
|
||||
/// of the hunk.
|
||||
int diffSrcLine;
|
||||
|
||||
/**
|
||||
* The index of the first line that was changed in the dst as returned by the
|
||||
* diff command. The diff command numbers lines starting at 1, but it
|
||||
* subtracts 1 from the line number if there are no lines on the destination
|
||||
* side of the hunk.
|
||||
*/
|
||||
/// The index of the first line that was changed in the dst as returned by the
|
||||
/// diff command. The diff command numbers lines starting at 1, but it
|
||||
/// subtracts 1 from the line number if there are no lines on the destination
|
||||
/// side of the hunk.
|
||||
int diffDstLine;
|
||||
|
||||
/**
|
||||
* A list of the individual lines that were removed from the src.
|
||||
*/
|
||||
/// A list of the individual lines that were removed from the src.
|
||||
List<String> removeLines = <String>[];
|
||||
|
||||
/**
|
||||
* A list of the individual lines that were added to the dst.
|
||||
*/
|
||||
/// A list of the individual lines that were added to the dst.
|
||||
List<String> addLines = <String>[];
|
||||
|
||||
/**
|
||||
* Initialize a newly created hunk. The lines will be added after the object
|
||||
* has been created.
|
||||
*/
|
||||
/// Initialize a newly created hunk. The lines will be added after the object
|
||||
/// has been created.
|
||||
DiffHunk(this.diffSrcLine, this.diffDstLine);
|
||||
|
||||
/**
|
||||
* Return the index of the first line that was changed in the dst. Unlike the
|
||||
* [diffDstLine] field, this getter adjusts the line number to be consistent
|
||||
* whether or not there were any changed lines.
|
||||
*/
|
||||
/// Return the index of the first line that was changed in the dst. Unlike the
|
||||
/// [diffDstLine] field, this getter adjusts the line number to be consistent
|
||||
/// whether or not there were any changed lines.
|
||||
int get dstLine {
|
||||
return addLines.isEmpty ? diffDstLine : diffDstLine - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index of the first line that was changed in the src. Unlike the
|
||||
* [diffDstLine] field, this getter adjusts the line number to be consistent
|
||||
* whether or not there were any changed lines.
|
||||
*/
|
||||
/// Return the index of the first line that was changed in the src. Unlike the
|
||||
/// [diffDstLine] field, this getter adjusts the line number to be consistent
|
||||
/// whether or not there were any changed lines.
|
||||
int get srcLine {
|
||||
return removeLines.isEmpty ? diffSrcLine : diffSrcLine - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A representation of a single line (record) from a raw diff.
|
||||
*/
|
||||
/// A representation of a single line (record) from a raw diff.
|
||||
class DiffRecord {
|
||||
/**
|
||||
* The repository containing the file(s) that were modified.
|
||||
*/
|
||||
/// The repository containing the file(s) that were modified.
|
||||
final GitRepository repository;
|
||||
|
||||
/**
|
||||
* The SHA1 of the blob in the src.
|
||||
*/
|
||||
/// The SHA1 of the blob in the src.
|
||||
final String srcBlob;
|
||||
|
||||
/**
|
||||
* The SHA1 of the blob in the dst.
|
||||
*/
|
||||
/// The SHA1 of the blob in the dst.
|
||||
final String dstBlob;
|
||||
|
||||
/**
|
||||
* The status of the change. Valid values are:
|
||||
* * A: addition of a file
|
||||
* * C: copy of a file into a new one
|
||||
* * D: deletion of a file
|
||||
* * M: modification of the contents or mode of a file
|
||||
* * R: renaming of a file
|
||||
* * T: change in the type of the file
|
||||
* * U: file is unmerged (you must complete the merge before it can be committed)
|
||||
* * X: "unknown" change type (most probably a bug, please report it)
|
||||
*
|
||||
* Status letters C and R are always followed by a score (denoting the
|
||||
* percentage of similarity between the source and target of the move or
|
||||
* copy), and are the only ones to be so.
|
||||
*/
|
||||
/// The status of the change. Valid values are:
|
||||
/// * A: addition of a file
|
||||
/// * C: copy of a file into a new one
|
||||
/// * D: deletion of a file
|
||||
/// * M: modification of the contents or mode of a file
|
||||
/// * R: renaming of a file
|
||||
/// * T: change in the type of the file
|
||||
/// * U: file is unmerged (you must complete the merge before it can be
|
||||
/// committed)
|
||||
/// * X: "unknown" change type (most probably a bug, please report it)
|
||||
///
|
||||
/// Status letters C and R are always followed by a score (denoting the
|
||||
/// percentage of similarity between the source and target of the move or
|
||||
/// copy), and are the only ones to be so.
|
||||
final String status;
|
||||
|
||||
/**
|
||||
* The path of the src.
|
||||
*/
|
||||
/// The path of the src.
|
||||
final String srcPath;
|
||||
|
||||
/**
|
||||
* The path of the dst if this was either a copy or a rename operation.
|
||||
*/
|
||||
/// The path of the dst if this was either a copy or a rename operation.
|
||||
final String dstPath;
|
||||
|
||||
/**
|
||||
* Initialize a newly created diff record.
|
||||
*/
|
||||
/// Initialize a newly created diff record.
|
||||
DiffRecord(this.repository, this.srcBlob, this.dstBlob, this.status,
|
||||
this.srcPath, this.dstPath);
|
||||
|
||||
/**
|
||||
* Return `true` if this record represents a file that was added.
|
||||
*/
|
||||
/// Return `true` if this record represents a file that was added.
|
||||
bool get isAddition => status == 'A';
|
||||
|
||||
/**
|
||||
* Return `true` if this record represents a file that was copied.
|
||||
*/
|
||||
/// Return `true` if this record represents a file that was copied.
|
||||
bool get isCopy => status.startsWith('C');
|
||||
|
||||
/**
|
||||
* Return `true` if this record represents a file that was deleted.
|
||||
*/
|
||||
/// Return `true` if this record represents a file that was deleted.
|
||||
bool get isDeletion => status == 'D';
|
||||
|
||||
/**
|
||||
* Return `true` if this record represents a file that was modified.
|
||||
*/
|
||||
/// Return `true` if this record represents a file that was modified.
|
||||
bool get isModification => status == 'M';
|
||||
|
||||
/**
|
||||
* Return `true` if this record represents a file that was renamed.
|
||||
*/
|
||||
/// Return `true` if this record represents a file that was renamed.
|
||||
bool get isRename => status.startsWith('R');
|
||||
|
||||
/**
|
||||
* Return `true` if this record represents an entity whose type was changed
|
||||
* (for example, from a file to a directory).
|
||||
*/
|
||||
/// Return `true` if this record represents an entity whose type was changed
|
||||
/// (for example, from a file to a directory).
|
||||
bool get isTypeChange => status == 'T';
|
||||
|
||||
/**
|
||||
* Return a representation of the individual blobs within this diff.
|
||||
*/
|
||||
/// Return a representation of the individual blobs within this diff.
|
||||
BlobDiff getBlobDiff() => repository.getBlobDiff(srcBlob, dstBlob);
|
||||
|
||||
/**
|
||||
* Return `true` if this diff applies to a file with the given name.
|
||||
*/
|
||||
/// Return `true` if this diff applies to a file with the given name.
|
||||
bool isFor(String fileName) =>
|
||||
(srcPath != null && fileName == path.basename(srcPath)) ||
|
||||
(dstPath != null && fileName == path.basename(dstPath));
|
||||
|
@ -385,42 +294,30 @@ class DiffRecord {
|
|||
String toString() => srcPath ?? dstPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* A representation of a git repository.
|
||||
*/
|
||||
/// A representation of a git repository.
|
||||
class GitRepository {
|
||||
/**
|
||||
* The absolute path of the directory containing the repository.
|
||||
*/
|
||||
/// The absolute path of the directory containing the repository.
|
||||
final String path;
|
||||
|
||||
/**
|
||||
* The logger to which git commands should be written, or `null` if the
|
||||
* commands should not be written.
|
||||
*/
|
||||
/// The logger to which git commands should be written, or `null` if the
|
||||
/// commands should not be written.
|
||||
final Logger logger;
|
||||
|
||||
/**
|
||||
* Initialize a newly created repository to represent the git repository at
|
||||
* the given [path].
|
||||
*
|
||||
* If a [commandSink] is provided, any calls to git will be written to it.
|
||||
*/
|
||||
/// Initialize a newly created repository to represent the git repository at
|
||||
/// the given [path].
|
||||
///
|
||||
/// If a [commandSink] is provided, any calls to git will be written to it.
|
||||
GitRepository(this.path, {this.logger});
|
||||
|
||||
/**
|
||||
* Checkout the given [commit] from the repository. This is done by running
|
||||
* the command `git checkout <sha>`.
|
||||
*/
|
||||
/// Checkout the given [commit] from the repository. This is done by running
|
||||
/// the command `git checkout <sha>`.
|
||||
void checkout(String commit) {
|
||||
_run(['checkout', commit]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return details about the differences between the two blobs identified by
|
||||
* the SHA1 of the [srcBlob] and the SHA1 of the [dstBlob]. This is done by
|
||||
* running the command `git diff <blob> <blob>`.
|
||||
*/
|
||||
/// Return details about the differences between the two blobs identified by
|
||||
/// the SHA1 of the [srcBlob] and the SHA1 of the [dstBlob]. This is done by
|
||||
/// running the command `git diff <blob> <blob>`.
|
||||
BlobDiff getBlobDiff(String srcBlob, String dstBlob) {
|
||||
ProcessResult result = _run(['diff', '-U0', srcBlob, dstBlob]);
|
||||
List<String> diffResults =
|
||||
|
@ -428,11 +325,9 @@ class GitRepository {
|
|||
return BlobDiff._(diffResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return details about the differences between the two commits identified by
|
||||
* the [srcCommit] and [dstCommit]. This is done by running the command
|
||||
* `git diff --raw --no-abbrev --no-renames -z <sha> <sha>`.
|
||||
*/
|
||||
/// Return details about the differences between the two commits identified by
|
||||
/// the [srcCommit] and [dstCommit]. This is done by running the command
|
||||
/// `git diff --raw --no-abbrev --no-renames -z <sha> <sha>`.
|
||||
CommitDelta getCommitDiff(String srcCommit, String dstCommit) {
|
||||
// Consider --find-renames instead of --no-renames if rename information is
|
||||
// desired.
|
||||
|
@ -448,10 +343,8 @@ class GitRepository {
|
|||
return CommitDelta._(this, result.stdout as String);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a representation of the history of this repository. This is done by
|
||||
* running the command `git rev-list --first-parent HEAD`.
|
||||
*/
|
||||
/// Return a representation of the history of this repository. This is done by
|
||||
/// running the command `git rev-list --first-parent HEAD`.
|
||||
LinearCommitHistory getCommitHistory() {
|
||||
ProcessResult result = _run(['rev-list', '--first-parent', 'HEAD']);
|
||||
List<String> commitIds =
|
||||
|
@ -459,10 +352,8 @@ class GitRepository {
|
|||
return LinearCommitHistory(this, commitIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously run the given [executable] with the given [arguments]. Return
|
||||
* the result of running the process.
|
||||
*/
|
||||
/// Synchronously run the given [executable] with the given [arguments].
|
||||
/// Return the result of running the process.
|
||||
ProcessResult _run(List<String> arguments) {
|
||||
logger?.log('git', 'git', arguments: arguments);
|
||||
return Process.runSync('git', arguments,
|
||||
|
@ -470,73 +361,49 @@ class GitRepository {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A representation of the history of a Git repository. This only represents a
|
||||
* single linear path in the history graph.
|
||||
*/
|
||||
/// A representation of the history of a Git repository. This only represents a
|
||||
/// single linear path in the history graph.
|
||||
class LinearCommitHistory {
|
||||
/**
|
||||
* The repository whose history is being represented.
|
||||
*/
|
||||
/// The repository whose history is being represented.
|
||||
final GitRepository repository;
|
||||
|
||||
/**
|
||||
* The id's (SHA's) of the commits in the repository, with the most recent
|
||||
* commit being first and the oldest commit being last.
|
||||
*/
|
||||
/// The id's (SHA's) of the commits in the repository, with the most recent
|
||||
/// commit being first and the oldest commit being last.
|
||||
final List<String> commitIds;
|
||||
|
||||
/**
|
||||
* Initialize a commit history for the given [repository] to have the given
|
||||
* [commitIds].
|
||||
*/
|
||||
/// Initialize a commit history for the given [repository] to have the given
|
||||
/// [commitIds].
|
||||
LinearCommitHistory(this.repository, this.commitIds);
|
||||
|
||||
/**
|
||||
* Return an iterator that can be used to iterate over this commit history.
|
||||
*/
|
||||
/// Return an iterator that can be used to iterate over this commit history.
|
||||
LinearCommitHistoryIterator iterator() {
|
||||
return LinearCommitHistoryIterator(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An iterator over the history of a Git repository.
|
||||
*/
|
||||
/// An iterator over the history of a Git repository.
|
||||
class LinearCommitHistoryIterator {
|
||||
/**
|
||||
* The commit history being iterated over.
|
||||
*/
|
||||
/// The commit history being iterated over.
|
||||
final LinearCommitHistory history;
|
||||
|
||||
/**
|
||||
* The index of the current commit in the list of [commitIds].
|
||||
*/
|
||||
/// The index of the current commit in the list of [commitIds].
|
||||
int currentCommit;
|
||||
|
||||
/**
|
||||
* Initialize a newly created iterator to iterate over the commits with the
|
||||
* given [commitIds];
|
||||
*/
|
||||
/// Initialize a newly created iterator to iterate over the commits with the
|
||||
/// given [commitIds];
|
||||
LinearCommitHistoryIterator(this.history) {
|
||||
currentCommit = history.commitIds.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SHA1 of the commit after the current commit (the 'dst' of the
|
||||
* [next] diff).
|
||||
*/
|
||||
/// Return the SHA1 of the commit after the current commit (the 'dst' of the
|
||||
/// [next] diff).
|
||||
String get dstCommit => history.commitIds[currentCommit - 1];
|
||||
|
||||
/**
|
||||
* Return the SHA1 of the current commit (the 'src' of the [next] diff).
|
||||
*/
|
||||
/// Return the SHA1 of the current commit (the 'src' of the [next] diff).
|
||||
String get srcCommit => history.commitIds[currentCommit];
|
||||
|
||||
/**
|
||||
* Advance to the next commit in the history. Return `true` if it is safe to
|
||||
* ask for the [next] diff.
|
||||
*/
|
||||
/// Advance to the next commit in the history. Return `true` if it is safe to
|
||||
/// ask for the [next] diff.
|
||||
bool moveNext() {
|
||||
if (currentCommit <= 1) {
|
||||
return false;
|
||||
|
@ -545,9 +412,7 @@ class LinearCommitHistoryIterator {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the difference between the current commit and the commit that
|
||||
* followed it.
|
||||
*/
|
||||
/// Return the difference between the current commit and the commit that
|
||||
/// followed it.
|
||||
CommitDelta next() => history.repository.getCommitDiff(srcCommit, dstCommit);
|
||||
}
|
||||
|
|
|
@ -2,37 +2,25 @@
|
|||
// 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.
|
||||
|
||||
/**
|
||||
* A utility class used to write logging information during a test.
|
||||
*/
|
||||
/// A utility class used to write logging information during a test.
|
||||
class Logger {
|
||||
/**
|
||||
* The width of the field in which labels are printed.
|
||||
*/
|
||||
/// The width of the field in which labels are printed.
|
||||
static const int _labelWidth = 8;
|
||||
|
||||
/**
|
||||
* The separator used to separate the label from the content.
|
||||
*/
|
||||
/// The separator used to separate the label from the content.
|
||||
static const String _separator = ' : ';
|
||||
|
||||
/**
|
||||
* The sink to which the logged information should be written.
|
||||
*/
|
||||
/// The sink to which the logged information should be written.
|
||||
final StringSink sink;
|
||||
|
||||
/**
|
||||
* Initialize a newly created logger to write to the given [sink].
|
||||
*/
|
||||
/// Initialize a newly created logger to write to the given [sink].
|
||||
Logger(this.sink);
|
||||
|
||||
/**
|
||||
* Log the given information.
|
||||
*
|
||||
* The [label] is used to indicate the kind of information being logged, while
|
||||
* the [content] contains the actual information. If a list of [arguments] is
|
||||
* provided, then they will be written after the content.
|
||||
*/
|
||||
/// Log the given information.
|
||||
///
|
||||
/// The [label] is used to indicate the kind of information being logged,
|
||||
/// while the [content] contains the actual information. If a list of
|
||||
/// [arguments] is provided, then they will be written after the content.
|
||||
void log(String label, String content, {List<String> arguments}) {
|
||||
for (int i = _labelWidth - label.length; i > 0; i--) {
|
||||
sink.write(' ');
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
// 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.
|
||||
|
||||
/**
|
||||
* Support for interacting with an analysis server that is running in a separate
|
||||
* process.
|
||||
*/
|
||||
/// Support for interacting with an analysis server that is running in a
|
||||
/// separate process.
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:convert' hide JsonDecoder;
|
||||
|
@ -19,30 +17,20 @@ import 'package:path/path.dart' as path;
|
|||
|
||||
import 'logger.dart';
|
||||
|
||||
/**
|
||||
* Return the current time expressed as milliseconds since the epoch.
|
||||
*/
|
||||
/// Return the current time expressed as milliseconds since the epoch.
|
||||
int get currentTime => DateTime.now().millisecondsSinceEpoch;
|
||||
|
||||
/**
|
||||
* ???
|
||||
*/
|
||||
/// ???
|
||||
class ErrorMap {
|
||||
/**
|
||||
* A table mapping file paths to the errors associated with that file.
|
||||
*/
|
||||
/// A table mapping file paths to the errors associated with that file.
|
||||
final Map<String, List<AnalysisError>> pathMap =
|
||||
HashMap<String, List<AnalysisError>>();
|
||||
|
||||
/**
|
||||
* Initialize a newly created error map.
|
||||
*/
|
||||
/// Initialize a newly created error map.
|
||||
ErrorMap();
|
||||
|
||||
/**
|
||||
* Initialize a newly created error map to contain the same mapping as the
|
||||
* given [errorMap].
|
||||
*/
|
||||
/// Initialize a newly created error map to contain the same mapping as the
|
||||
/// given [errorMap].
|
||||
ErrorMap.from(ErrorMap errorMap) {
|
||||
pathMap.addAll(errorMap.pathMap);
|
||||
}
|
||||
|
@ -52,60 +40,38 @@ class ErrorMap {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data that has been collected about a request sent to the server.
|
||||
*/
|
||||
/// Data that has been collected about a request sent to the server.
|
||||
class RequestData {
|
||||
/**
|
||||
* The unique id of the request.
|
||||
*/
|
||||
/// The unique id of the request.
|
||||
final String id;
|
||||
|
||||
/**
|
||||
* The method that was requested.
|
||||
*/
|
||||
/// The method that was requested.
|
||||
final String method;
|
||||
|
||||
/**
|
||||
* The request parameters.
|
||||
*/
|
||||
/// The request parameters.
|
||||
final Map<String, dynamic> params;
|
||||
|
||||
/**
|
||||
* The time at which the request was sent.
|
||||
*/
|
||||
/// The time at which the request was sent.
|
||||
final int requestTime;
|
||||
|
||||
/**
|
||||
* The time at which the response was received, or `null` if no response has
|
||||
* been received.
|
||||
*/
|
||||
/// The time at which the response was received, or `null` if no response has
|
||||
/// been received.
|
||||
int responseTime;
|
||||
|
||||
/**
|
||||
* The response that was received.
|
||||
*/
|
||||
/// The response that was received.
|
||||
Response _response;
|
||||
|
||||
/**
|
||||
* The completer that will be completed when a response is received.
|
||||
*/
|
||||
/// The completer that will be completed when a response is received.
|
||||
Completer<Response> _responseCompleter;
|
||||
|
||||
/**
|
||||
* Initialize a newly created set of request data.
|
||||
*/
|
||||
/// Initialize a newly created set of request data.
|
||||
RequestData(this.id, this.method, this.params, this.requestTime);
|
||||
|
||||
/**
|
||||
* Return the number of milliseconds that elapsed between the request and the
|
||||
* response. This getter assumes that the response was received.
|
||||
*/
|
||||
/// Return the number of milliseconds that elapsed between the request and the
|
||||
/// response. This getter assumes that the response was received.
|
||||
int get elapsedTime => responseTime - requestTime;
|
||||
|
||||
/**
|
||||
* Return a future that will complete when a response is received.
|
||||
*/
|
||||
/// Return a future that will complete when a response is received.
|
||||
Future<Response> get respondedTo {
|
||||
if (_response != null) {
|
||||
return Future.value(_response);
|
||||
|
@ -114,9 +80,7 @@ class RequestData {
|
|||
return _responseCompleter.future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that the given [response] was received.
|
||||
*/
|
||||
/// Record that the given [response] was received.
|
||||
void recordResponse(Response response) {
|
||||
if (_response != null) {
|
||||
stdout.writeln(
|
||||
|
@ -132,113 +96,80 @@ class RequestData {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility for starting and communicating with an analysis server that is
|
||||
* running in a separate process.
|
||||
*/
|
||||
/// A utility for starting and communicating with an analysis server that is
|
||||
/// running in a separate process.
|
||||
class Server {
|
||||
/**
|
||||
* The label used for communications from the client.
|
||||
*/
|
||||
/// The label used for communications from the client.
|
||||
static const String fromClient = 'client';
|
||||
|
||||
/**
|
||||
* The label used for normal communications from the server.
|
||||
*/
|
||||
/// The label used for normal communications from the server.
|
||||
static const String fromServer = 'server';
|
||||
|
||||
/**
|
||||
* The label used for output written by the server on [fromStderr].
|
||||
*/
|
||||
/// The label used for output written by the server on [fromStderr].
|
||||
static const String fromStderr = 'stderr';
|
||||
|
||||
/**
|
||||
* The logger to which the communications log should be written, or `null` if
|
||||
* the log should not be written.
|
||||
*/
|
||||
/// The logger to which the communications log should be written, or `null` if
|
||||
/// the log should not be written.
|
||||
final Logger logger;
|
||||
|
||||
/**
|
||||
* The process in which the server is running, or `null` if the server hasn't
|
||||
* been started yet.
|
||||
*/
|
||||
/// The process in which the server is running, or `null` if the server hasn't
|
||||
/// been started yet.
|
||||
Process _process;
|
||||
|
||||
/**
|
||||
* Number that should be used to compute the 'id' to send in the next command
|
||||
* sent to the server.
|
||||
*/
|
||||
/// Number that should be used to compute the 'id' to send in the next command
|
||||
/// sent to the server.
|
||||
int _nextId = 0;
|
||||
|
||||
/**
|
||||
* The analysis roots that are included.
|
||||
*/
|
||||
/// The analysis roots that are included.
|
||||
List<String> _analysisRootIncludes = <String>[];
|
||||
|
||||
/**
|
||||
* A list containing the paths of files for which an overlay has been created.
|
||||
*/
|
||||
/// A list containing the paths of files for which an overlay has been
|
||||
/// created.
|
||||
List<String> filesWithOverlays = <String>[];
|
||||
|
||||
/**
|
||||
* The files that the server reported as being analyzed.
|
||||
*/
|
||||
/// The files that the server reported as being analyzed.
|
||||
List<String> _analyzedFiles = <String>[];
|
||||
|
||||
/// A mapping from the absolute paths of files to the most recent set of
|
||||
/// errors received for that file.
|
||||
final ErrorMap _errorMap = ErrorMap();
|
||||
|
||||
/**
|
||||
* The completer that will be completed the next time a 'server.status'
|
||||
* notification is received from the server with 'analyzing' set to false.
|
||||
*/
|
||||
/// The completer that will be completed the next time a 'server.status'
|
||||
/// notification is received from the server with 'analyzing' set to false.
|
||||
Completer<void> _analysisFinishedCompleter;
|
||||
|
||||
/**
|
||||
* The completer that will be completed the next time a 'server.connected'
|
||||
* notification is received from the server.
|
||||
*/
|
||||
/// The completer that will be completed the next time a 'server.connected'
|
||||
/// notification is received from the server.
|
||||
Completer<void> _serverConnectedCompleter;
|
||||
|
||||
/**
|
||||
* A table mapping the ids of requests that have been sent to the server to
|
||||
* data about those requests.
|
||||
*/
|
||||
/// A table mapping the ids of requests that have been sent to the server to
|
||||
/// data about those requests.
|
||||
final Map<String, RequestData> _requestDataMap = <String, RequestData>{};
|
||||
|
||||
/**
|
||||
* A table mapping the number of times a request whose 'event' is equal to the
|
||||
* key was sent to the server.
|
||||
*/
|
||||
/// A table mapping the number of times a request whose 'event' is equal to
|
||||
/// the key was sent to the server.
|
||||
final Map<String, int> _notificationCountMap = <String, int>{};
|
||||
|
||||
/**
|
||||
* Initialize a new analysis server. The analysis server is not running and
|
||||
* must be started using [start].
|
||||
*
|
||||
* If a [logger] is provided, the communications between the client (this
|
||||
* test) and the server will be written to it.
|
||||
*/
|
||||
/// Initialize a new analysis server. The analysis server is not running and
|
||||
/// must be started using [start].
|
||||
///
|
||||
/// If a [logger] is provided, the communications between the client (this
|
||||
/// test) and the server will be written to it.
|
||||
Server({this.logger});
|
||||
|
||||
/**
|
||||
* Return a future that will complete when a 'server.status' notification is
|
||||
* received from the server with 'analyzing' set to false.
|
||||
*
|
||||
* The future will only be completed by 'server.status' notifications that are
|
||||
* received after this function call, so it is safe to use this getter
|
||||
* multiple times in one test; each time it is used it will wait afresh for
|
||||
* analysis to finish.
|
||||
*/
|
||||
/// Return a future that will complete when a 'server.status' notification is
|
||||
/// received from the server with 'analyzing' set to false.
|
||||
///
|
||||
/// The future will only be completed by 'server.status' notifications that
|
||||
/// are received after this function call, so it is safe to use this getter
|
||||
/// multiple times in one test; each time it is used it will wait afresh for
|
||||
/// analysis to finish.
|
||||
Future get analysisFinished {
|
||||
_analysisFinishedCompleter ??= Completer<void>();
|
||||
return _analysisFinishedCompleter.future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the paths of files that are currently being analyzed.
|
||||
*/
|
||||
/// Return a list of the paths of files that are currently being analyzed.
|
||||
List<String> get analyzedDartFiles {
|
||||
bool isAnalyzed(String filePath) {
|
||||
// TODO(brianwilkerson) This should use the path package to determine
|
||||
|
@ -260,17 +191,13 @@ class Server {
|
|||
return analyzedFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a table mapping the absolute paths of files to the most recent set
|
||||
* of errors received for that file. The content of the map will not change
|
||||
* when new sets of errors are received.
|
||||
*/
|
||||
/// Return a table mapping the absolute paths of files to the most recent set
|
||||
/// of errors received for that file. The content of the map will not change
|
||||
/// when new sets of errors are received.
|
||||
ErrorMap get errorMap => ErrorMap.from(_errorMap);
|
||||
|
||||
/**
|
||||
* Compute a mapping from each of the file paths in the given list of
|
||||
* [filePaths] to the list of errors in the file at that path.
|
||||
*/
|
||||
/// Compute a mapping from each of the file paths in the given list of
|
||||
/// [filePaths] to the list of errors in the file at that path.
|
||||
Future<ErrorMap> computeErrorMap(List<String> filePaths) async {
|
||||
ErrorMap errorMap = ErrorMap();
|
||||
List<Future> futures = <Future>[];
|
||||
|
@ -288,9 +215,7 @@ class Server {
|
|||
return errorMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print information about the communications with the server.
|
||||
*/
|
||||
/// Print information about the communications with the server.
|
||||
void printStatistics() {
|
||||
void writeSpaces(int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
|
@ -381,9 +306,7 @@ class Server {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any existing overlays.
|
||||
*/
|
||||
/// Remove any existing overlays.
|
||||
void removeAllOverlays() {
|
||||
Map<String, dynamic> files = HashMap<String, dynamic>();
|
||||
for (String path in filesWithOverlays) {
|
||||
|
@ -584,20 +507,18 @@ class Server {
|
|||
_send('server.shutdown', null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server and listen for communications from it.
|
||||
*
|
||||
* If [checked] is `true`, the server's VM will be running in checked mode.
|
||||
*
|
||||
* If [diagnosticPort] is not `null`, the server will serve status pages to
|
||||
* the specified port.
|
||||
*
|
||||
* If [profileServer] is `true`, the server will be started with "--observe"
|
||||
* and "--pause-isolates-on-exit", allowing the observatory to be used.
|
||||
*
|
||||
* If [useAnalysisHighlight2] is `true`, the server will use the new highlight
|
||||
* APIs.
|
||||
*/
|
||||
/// Start the server and listen for communications from it.
|
||||
///
|
||||
/// If [checked] is `true`, the server's VM will be running in checked mode.
|
||||
///
|
||||
/// If [diagnosticPort] is not `null`, the server will serve status pages to
|
||||
/// the specified port.
|
||||
///
|
||||
/// If [profileServer] is `true`, the server will be started with "--observe"
|
||||
/// and "--pause-isolates-on-exit", allowing the observatory to be used.
|
||||
///
|
||||
/// If [useAnalysisHighlight2] is `true`, the server will use the new
|
||||
/// highlight APIs.
|
||||
Future<void> start(
|
||||
{bool checked = true,
|
||||
int diagnosticPort,
|
||||
|
@ -663,10 +584,8 @@ class Server {
|
|||
return _serverConnectedCompleter.future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the root directory of the analysis_server package by proceeding
|
||||
* upward to the 'test' dir, and then going up one more directory.
|
||||
*/
|
||||
/// Find the root directory of the analysis_server package by proceeding
|
||||
/// upward to the 'test' dir, and then going up one more directory.
|
||||
String _findRoot(String pathname) {
|
||||
while (!['benchmark', 'test'].contains(path.basename(pathname))) {
|
||||
String parent = path.dirname(pathname);
|
||||
|
@ -678,9 +597,7 @@ class Server {
|
|||
return path.dirname(pathname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a [notification] received from the server.
|
||||
*/
|
||||
/// Handle a [notification] received from the server.
|
||||
void _handleNotification(Notification notification) {
|
||||
switch (notification.event) {
|
||||
case 'server.connected':
|
||||
|
@ -753,9 +670,7 @@ class Server {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a [response] received from the server.
|
||||
*/
|
||||
/// Handle a [response] received from the server.
|
||||
void _handleResponse(Response response) {
|
||||
String id = response.id.toString();
|
||||
RequestData requestData = _requestDataMap[id];
|
||||
|
@ -832,23 +747,17 @@ class Server {
|
|||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a [line] of input read from stderr.
|
||||
*/
|
||||
/// Handle a [line] of input read from stderr.
|
||||
void _handleStdErr(String line) {
|
||||
String trimmedLine = line.trim();
|
||||
logger?.log(fromStderr, '$trimmedLine');
|
||||
throw StateError('Message received on stderr: "$trimmedLine"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a [line] of input read from stdout.
|
||||
*/
|
||||
/// Handle a [line] of input read from stdout.
|
||||
void _handleStdOut(String line) {
|
||||
/**
|
||||
* Cast the given [value] to a Map, or throw an [ArgumentError] if the value
|
||||
* cannot be cast.
|
||||
*/
|
||||
/// Cast the given [value] to a Map, or throw an [ArgumentError] if the
|
||||
/// value cannot be cast.
|
||||
Map asMap(Object value) {
|
||||
if (value is Map) {
|
||||
return value;
|
||||
|
@ -876,14 +785,10 @@ class Server {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening to output from the server.
|
||||
*/
|
||||
/// Start listening to output from the server.
|
||||
void _listenToOutput() {
|
||||
/**
|
||||
* Install the given [handler] to listen to transformed output from the
|
||||
* given [stream].
|
||||
*/
|
||||
/// Install the given [handler] to listen to transformed output from the
|
||||
/// given [stream].
|
||||
void installHandler(
|
||||
Stream<List<int>> stream, void Function(String) handler) {
|
||||
stream
|
||||
|
@ -896,9 +801,7 @@ class Server {
|
|||
installHandler(_process.stderr, _handleStdErr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a command to the server. An 'id' will be automatically assigned.
|
||||
*/
|
||||
/// Send a command to the server. An 'id' will be automatically assigned.
|
||||
RequestData _send(String method, Map<String, dynamic> params,
|
||||
{void Function(Response) onResponse}) {
|
||||
String id = '${_nextId++}';
|
||||
|
|
|
@ -10,10 +10,8 @@ import 'package:path/path.dart';
|
|||
|
||||
import '../timing_framework.dart';
|
||||
|
||||
/**
|
||||
* Perform the timing test, printing the minimum, average and maximum times, as
|
||||
* well as the standard deviation to the output.
|
||||
*/
|
||||
/// Perform the timing test, printing the minimum, average and maximum times, as
|
||||
/// well as the standard deviation to the output.
|
||||
void main(List<String> args) {
|
||||
SimpleTest test = SimpleTest();
|
||||
test.run().then((TimingResult result) {
|
||||
|
@ -27,35 +25,23 @@ void main(List<String> args) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A test of how long it takes to get code completion results after making a
|
||||
* minor change inside a method body.
|
||||
*/
|
||||
/// A test of how long it takes to get code completion results after making a
|
||||
/// minor change inside a method body.
|
||||
class SimpleTest extends TimingTest {
|
||||
/**
|
||||
* The path to the file in which code completion is to be performed.
|
||||
*/
|
||||
/// The path to the file in which code completion is to be performed.
|
||||
String mainFilePath;
|
||||
|
||||
/**
|
||||
* The original content of the file.
|
||||
*/
|
||||
/// The original content of the file.
|
||||
String originalContent;
|
||||
|
||||
/**
|
||||
* The offset of the cursor when requesting code completion.
|
||||
*/
|
||||
/// The offset of the cursor when requesting code completion.
|
||||
int cursorOffset;
|
||||
|
||||
/**
|
||||
* A completer that will be completed when code completion results have been
|
||||
* received from the server.
|
||||
*/
|
||||
/// A completer that will be completed when code completion results have been
|
||||
/// received from the server.
|
||||
Completer completionReceived;
|
||||
|
||||
/**
|
||||
* Initialize a newly created test.
|
||||
*/
|
||||
/// Initialize a newly created test.
|
||||
SimpleTest();
|
||||
|
||||
@override
|
||||
|
|
|
@ -11,38 +11,26 @@ import 'package:path/path.dart';
|
|||
import '../integration/support/integration_test_methods.dart';
|
||||
import '../integration/support/integration_tests.dart';
|
||||
|
||||
/**
|
||||
* Instances of the class [TimingResult] represent the timing information
|
||||
* gathered while executing a given timing test.
|
||||
*/
|
||||
/// Instances of the class [TimingResult] represent the timing information
|
||||
/// gathered while executing a given timing test.
|
||||
class TimingResult {
|
||||
/**
|
||||
* The number of nanoseconds in a millisecond.
|
||||
*/
|
||||
/// The number of nanoseconds in a millisecond.
|
||||
static int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
/**
|
||||
* The amount of time spent executing each test, in nanoseconds.
|
||||
*/
|
||||
/// The amount of time spent executing each test, in nanoseconds.
|
||||
List<int> times;
|
||||
|
||||
/**
|
||||
* Initialize a newly created timing result.
|
||||
*/
|
||||
/// Initialize a newly created timing result.
|
||||
TimingResult(this.times);
|
||||
|
||||
/**
|
||||
* The average amount of time spent executing a single iteration, in
|
||||
* milliseconds.
|
||||
*/
|
||||
/// The average amount of time spent executing a single iteration, in
|
||||
/// milliseconds.
|
||||
int get averageTime {
|
||||
return totalTime ~/ times.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum amount of time spent executing a single iteration, in
|
||||
* milliseconds.
|
||||
*/
|
||||
/// The maximum amount of time spent executing a single iteration, in
|
||||
/// milliseconds.
|
||||
int get maxTime {
|
||||
int maxTime = 0;
|
||||
int count = times.length;
|
||||
|
@ -52,10 +40,8 @@ class TimingResult {
|
|||
return maxTime ~/ NANOSECONDS_PER_MILLISECOND;
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum amount of time spent executing a single iteration, in
|
||||
* milliseconds.
|
||||
*/
|
||||
/// The minimum amount of time spent executing a single iteration, in
|
||||
/// milliseconds.
|
||||
int get minTime {
|
||||
int minTime = times[0];
|
||||
int count = times.length;
|
||||
|
@ -65,16 +51,12 @@ class TimingResult {
|
|||
return minTime ~/ NANOSECONDS_PER_MILLISECOND;
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard deviation of the times.
|
||||
*/
|
||||
/// The standard deviation of the times.
|
||||
double get standardDeviation {
|
||||
return computeStandardDeviation(toMilliseconds(times));
|
||||
}
|
||||
|
||||
/**
|
||||
* The total amount of time spent executing the test, in milliseconds.
|
||||
*/
|
||||
/// The total amount of time spent executing the test, in milliseconds.
|
||||
int get totalTime {
|
||||
int totalTime = 0;
|
||||
int count = times.length;
|
||||
|
@ -84,9 +66,7 @@ class TimingResult {
|
|||
return totalTime ~/ NANOSECONDS_PER_MILLISECOND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the standard deviation of the given set of [values].
|
||||
*/
|
||||
/// Compute the standard deviation of the given set of [values].
|
||||
double computeStandardDeviation(List<int> values) {
|
||||
int count = values.length;
|
||||
double sumOfValues = 0;
|
||||
|
@ -102,10 +82,8 @@ class TimingResult {
|
|||
return sqrt((sumOfDiffSquared / (count - 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given [times], expressed in nanoseconds, to times expressed in
|
||||
* milliseconds.
|
||||
*/
|
||||
/// Convert the given [times], expressed in nanoseconds, to times expressed in
|
||||
/// milliseconds.
|
||||
List<int> toMilliseconds(List<int> times) {
|
||||
int count = times.length;
|
||||
List<int> convertedValues = <int>[];
|
||||
|
@ -116,75 +94,50 @@ class TimingResult {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The abstract class [TimingTest] defines the behavior of objects that measure
|
||||
* the time required to perform some sequence of server operations.
|
||||
*/
|
||||
/// The abstract class [TimingTest] defines the behavior of objects that measure
|
||||
/// the time required to perform some sequence of server operations.
|
||||
abstract class TimingTest extends IntegrationTestMixin {
|
||||
/**
|
||||
* The number of times the test will be performed in order to warm up the VM.
|
||||
*/
|
||||
/// The number of times the test will be performed in order to warm up the VM.
|
||||
static final int DEFAULT_WARMUP_COUNT = 10;
|
||||
|
||||
/**
|
||||
* The number of times the test will be performed in order to compute a time.
|
||||
*/
|
||||
/// The number of times the test will be performed in order to compute a time.
|
||||
static final int DEFAULT_TIMING_COUNT = 10;
|
||||
|
||||
/**
|
||||
* The file suffix used to identify Dart files.
|
||||
*/
|
||||
/// The file suffix used to identify Dart files.
|
||||
static final String DART_SUFFIX = '.dart';
|
||||
|
||||
/**
|
||||
* The file suffix used to identify HTML files.
|
||||
*/
|
||||
/// The file suffix used to identify HTML files.
|
||||
static final String HTML_SUFFIX = '.html';
|
||||
|
||||
/**
|
||||
* The amount of time to give the server to respond to a shutdown request
|
||||
* before forcibly terminating it.
|
||||
*/
|
||||
/// The amount of time to give the server to respond to a shutdown request
|
||||
/// before forcibly terminating it.
|
||||
static const Duration SHUTDOWN_TIMEOUT = Duration(seconds: 5);
|
||||
|
||||
/**
|
||||
* The connection to the analysis server.
|
||||
*/
|
||||
/// The connection to the analysis server.
|
||||
@override
|
||||
Server server;
|
||||
|
||||
/**
|
||||
* The temporary directory in which source files can be stored.
|
||||
*/
|
||||
/// The temporary directory in which source files can be stored.
|
||||
Directory sourceDirectory;
|
||||
|
||||
/**
|
||||
* A flag indicating whether the teardown process should skip sending a
|
||||
* "server.shutdown" request because the server is known to have already
|
||||
* shutdown.
|
||||
*/
|
||||
/// A flag indicating whether the teardown process should skip sending a
|
||||
/// "server.shutdown" request because the server is known to have already
|
||||
/// shutdown.
|
||||
bool skipShutdown = false;
|
||||
|
||||
/**
|
||||
* Initialize a newly created test.
|
||||
*/
|
||||
/// Initialize a newly created test.
|
||||
TimingTest();
|
||||
|
||||
/**
|
||||
* Return the number of iterations that should be performed in order to
|
||||
* compute a time.
|
||||
*/
|
||||
/// Return the number of iterations that should be performed in order to
|
||||
/// compute a time.
|
||||
int get timingCount => DEFAULT_TIMING_COUNT;
|
||||
|
||||
/**
|
||||
* Return the number of iterations that should be performed in order to warm
|
||||
* up the VM.
|
||||
*/
|
||||
/// Return the number of iterations that should be performed in order to warm
|
||||
/// up the VM.
|
||||
int get warmupCount => DEFAULT_WARMUP_COUNT;
|
||||
|
||||
/**
|
||||
* Perform any operations that need to be performed once before any iterations.
|
||||
*/
|
||||
/// Perform any operations that need to be performed once before any
|
||||
/// iterations.
|
||||
Future oneTimeSetUp() {
|
||||
initializeInttestMixin();
|
||||
server = Server();
|
||||
|
@ -203,26 +156,21 @@ abstract class TimingTest extends IntegrationTestMixin {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any operations that need to be performed once after all iterations.
|
||||
*/
|
||||
/// Perform any operations that need to be performed once after all
|
||||
/// iterations.
|
||||
Future oneTimeTearDown() {
|
||||
return _shutdownIfNeeded().then((_) {
|
||||
sourceDirectory.deleteSync(recursive: true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any operations that part of a single iteration. It is the execution
|
||||
* of this method that will be measured.
|
||||
*/
|
||||
/// Perform any operations that part of a single iteration. It is the
|
||||
/// execution of this method that will be measured.
|
||||
Future perform();
|
||||
|
||||
/**
|
||||
* Return a future that will complete with a timing result representing the
|
||||
* number of milliseconds required to perform the operation the specified
|
||||
* number of times.
|
||||
*/
|
||||
/// Return a future that will complete with a timing result representing the
|
||||
/// number of milliseconds required to perform the operation the specified
|
||||
/// number of times.
|
||||
Future<TimingResult> run() async {
|
||||
List<int> times = <int>[];
|
||||
await oneTimeSetUp();
|
||||
|
@ -232,50 +180,38 @@ abstract class TimingTest extends IntegrationTestMixin {
|
|||
return Future<TimingResult>.value(TimingResult(times));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any operations that need to be performed before each iteration.
|
||||
*/
|
||||
/// Perform any operations that need to be performed before each iteration.
|
||||
Future setUp();
|
||||
|
||||
/**
|
||||
* Convert the given [relativePath] to an absolute path, by interpreting it
|
||||
* relative to [sourceDirectory]. On Windows any forward slashes in
|
||||
* [relativePath] are converted to backslashes.
|
||||
*/
|
||||
/// Convert the given [relativePath] to an absolute path, by interpreting it
|
||||
/// relative to [sourceDirectory]. On Windows any forward slashes in
|
||||
/// [relativePath] are converted to backslashes.
|
||||
String sourcePath(String relativePath) {
|
||||
return join(sourceDirectory.path, relativePath.replaceAll('/', separator));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform any operations that need to be performed after each iteration.
|
||||
*/
|
||||
/// Perform any operations that need to be performed after each iteration.
|
||||
Future tearDown();
|
||||
|
||||
/**
|
||||
* Write a source file with the given absolute [pathname] and [contents].
|
||||
*
|
||||
* If the file didn't previously exist, it is created. If it did, it is
|
||||
* overwritten.
|
||||
*
|
||||
* Parent directories are created as necessary.
|
||||
*/
|
||||
/// Write a source file with the given absolute [pathname] and [contents].
|
||||
///
|
||||
/// If the file didn't previously exist, it is created. If it did, it is
|
||||
/// overwritten.
|
||||
///
|
||||
/// Parent directories are created as necessary.
|
||||
void writeFile(String pathname, String contents) {
|
||||
Directory(dirname(pathname)).createSync(recursive: true);
|
||||
File(pathname).writeAsStringSync(contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of nanoseconds that have elapsed since the given
|
||||
* [stopwatch] was last stopped.
|
||||
*/
|
||||
/// Return the number of nanoseconds that have elapsed since the given
|
||||
/// [stopwatch] was last stopped.
|
||||
int _elapsedNanoseconds(Stopwatch stopwatch) {
|
||||
return (stopwatch.elapsedTicks * 1000000000) ~/ stopwatch.frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeatedly execute this test [count] times, adding timing information to
|
||||
* the given list of [times] if it is non-`null`.
|
||||
*/
|
||||
/// Repeatedly execute this test [count] times, adding timing information to
|
||||
/// the given list of [times] if it is non-`null`.
|
||||
Future _repeat(int count, List<int> times) {
|
||||
Stopwatch stopwatch = Stopwatch();
|
||||
return setUp().then((_) {
|
||||
|
@ -296,9 +232,7 @@ abstract class TimingTest extends IntegrationTestMixin {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut the server down unless [skipShutdown] is `true`.
|
||||
*/
|
||||
/// Shut the server down unless [skipShutdown] is `true`.
|
||||
Future _shutdownIfNeeded() {
|
||||
if (skipShutdown) {
|
||||
return Future.value();
|
||||
|
|
Loading…
Reference in a new issue