Add utilities for creating SourceChanges

R=scheglov@google.com

Review URL: https://codereview.chromium.org//1110583002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@45461 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
brianwilkerson@google.com 2015-04-30 14:56:55 +00:00
parent c014b52640
commit d741aaf58d
9 changed files with 1611 additions and 0 deletions

View file

@ -0,0 +1,249 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library analysis_server.src.utilities.change_builder_core;
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/utilities/change_builder_core.dart';
import 'package:analyzer/src/generated/source.dart';
/**
* A builder used to build a [SourceChange].
*/
class ChangeBuilderImpl implements ChangeBuilder {
/**
* The end-of-line marker used in the file being edited, or `null` if the
* default marker should be used.
*/
String eol = null;
/**
* The change that is being built.
*/
final SourceChange _change = new SourceChange('');
/**
* A table mapping group ids to the associated linked edit groups.
*/
final Map<String, LinkedEditGroup> _linkedEditGroups =
<String, LinkedEditGroup>{};
/**
* Initialize a newly created change builder.
*/
ChangeBuilderImpl();
@override
SourceChange get sourceChange {
_linkedEditGroups.forEach((String name, LinkedEditGroup group) {
_change.addLinkedEditGroup(group);
});
_linkedEditGroups.clear();
return _change;
}
@override
void addFileEdit(Source source, int fileStamp,
void buildFileEdit(FileEditBuilder builder)) {
FileEditBuilderImpl builder = createFileEditBuilder(source, fileStamp);
try {
buildFileEdit(builder);
} finally {
_change.addFileEdit(builder.fileEdit);
}
}
/**
* Create and return a [FileEditBuilder] that can be used to build edits to
* the given [source].
*/
FileEditBuilderImpl createFileEditBuilder(Source source, int fileStamp) {
return new FileEditBuilderImpl(this, source, fileStamp);
}
/**
* Return the linked edit group with the given [groupName], creating it if it
* did not already exist.
*/
LinkedEditGroup getLinkedEditGroup(String groupName) {
LinkedEditGroup group = _linkedEditGroups[groupName];
if (group == null) {
group = new LinkedEditGroup.empty();
_linkedEditGroups[groupName] = group;
}
return group;
}
}
/**
* A builder used to build a [SourceEdit] as part of a [SourceFileEdit].
*/
class EditBuilderImpl implements EditBuilder {
/**
* The builder being used to create the source file edit of which the source
* edit will be a part.
*/
final FileEditBuilderImpl fileEditBuilder;
/**
* The offset of the region being replaced.
*/
final int offset;
/**
* The length of the region being replaced.
*/
final int length;
/**
* The end-of-line marker used in the file being edited, or `null` if the
* default marker should be used.
*/
String _eol = null;
/**
* The buffer in which the content of the edit is being composed.
*/
final StringBuffer _buffer = new StringBuffer();
/**
* Initialize a newly created builder to build a source edit.
*/
EditBuilderImpl(this.fileEditBuilder, this.offset, this.length) {
_eol = fileEditBuilder.changeBuilder.eol;
}
/**
* Create and return an edit representing the replacement of a region of the
* file with the accumulated text.
*/
SourceEdit get sourceEdit =>
new SourceEdit(offset, length, _buffer.toString());
@override
void addLinkedEdit(
String groupName, void buildLinkedEdit(LinkedEditBuilder builder)) {
LinkedEditBuilderImpl builder = createLinkedEditBuilder();
int start = offset + _buffer.length;
try {
buildLinkedEdit(builder);
} finally {
int end = offset + _buffer.length;
int length = end - start;
Position position = new Position(fileEditBuilder.fileEdit.file, start);
LinkedEditGroup group =
fileEditBuilder.changeBuilder.getLinkedEditGroup(groupName);
group.addPosition(position, length);
for (LinkedEditSuggestion suggestion in builder.suggestions) {
group.addSuggestion(suggestion);
}
}
}
LinkedEditBuilderImpl createLinkedEditBuilder() {
return new LinkedEditBuilderImpl(this);
}
@override
void write(String string) {
_buffer.write(string);
}
@override
void writeln([String string]) {
_buffer.write(string);
if (_eol == null) {
_buffer.writeln();
} else {
_buffer.write(_eol);
}
}
}
/**
* A builder used to build a [SourceFileEdit] within a [SourceChange].
*/
class FileEditBuilderImpl implements FileEditBuilder {
/**
* The builder being used to create the source change of which the source file
* edit will be a part.
*/
final ChangeBuilderImpl changeBuilder;
/**
* The source file edit that is being built.
*/
final SourceFileEdit fileEdit;
/**
* Initialize a newly created builder to build a source file edit within the
* change being built by the given [changeBuilder]. The file being edited has
* the given [timeStamp] and [timeStamp].
*/
FileEditBuilderImpl(this.changeBuilder, Source source, int timeStamp)
: fileEdit = new SourceFileEdit(source.fullName, timeStamp);
@override
void addInsertion(int offset, void buildEdit(EditBuilder builder)) {
EditBuilderImpl builder = createEditBuilder(offset, 0);
try {
buildEdit(builder);
} finally {
fileEdit.add(builder.sourceEdit);
}
}
@override
void addLinkedPosition(int offset, int length, String groupName) {
LinkedEditGroup group = changeBuilder.getLinkedEditGroup(groupName);
Position position = new Position(fileEdit.file, offset);
group.addPosition(position, length);
}
@override
void addReplacement(
int offset, int length, void buildEdit(EditBuilder builder)) {
EditBuilderImpl builder = createEditBuilder(offset, length);
try {
buildEdit(builder);
} finally {
fileEdit.add(builder.sourceEdit);
}
}
EditBuilderImpl createEditBuilder(int offset, int length) {
return new EditBuilderImpl(this, offset, length);
}
}
/**
* A builder used to build a [LinkedEdit] region within an edit.
*/
class LinkedEditBuilderImpl implements LinkedEditBuilder {
final EditBuilderImpl editBuilder;
final List<LinkedEditSuggestion> suggestions = <LinkedEditSuggestion>[];
LinkedEditBuilderImpl(this.editBuilder);
@override
void addSuggestion(LinkedEditSuggestionKind kind, String value) {
suggestions.add(new LinkedEditSuggestion(value, kind));
}
@override
void addSuggestions(LinkedEditSuggestionKind kind, List<String> values) {
values.forEach((value) => addSuggestion(kind, value));
}
@override
void write(String string) {
editBuilder.write(string);
}
@override
void writeln([String string]) {
editBuilder.writeln(string);
}
}

View file

@ -0,0 +1,412 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library analysis_server.src.utilities.change_builder_dart;
import 'package:analysis_server/src/protocol.dart' hide ElementKind;
import 'package:analysis_server/src/services/correction/name_suggestion.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analysis_server/src/utilities/change_builder_core.dart';
import 'package:analysis_server/utilities/change_builder_core.dart';
import 'package:analysis_server/utilities/change_builder_dart.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
/**
* A [ChangeBuilder] used to build changes in Dart files.
*/
class DartChangeBuilderImpl extends ChangeBuilderImpl
implements DartChangeBuilder {
/**
* The analysis context in which the files being edited were analyzed.
*/
final AnalysisContext context;
/**
* Initialize a newly created change builder.
*/
DartChangeBuilderImpl(this.context);
@override
DartFileEditBuilderImpl createFileEditBuilder(Source source, int fileStamp) {
return new DartFileEditBuilderImpl(this, source, fileStamp);
}
}
/**
* An [EditBuilder] used to build edits in Dart files.
*/
class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
/**
* The string used when writing the 'abstract' modifier.
*/
static const String ABSTRACT_MODIFIER = 'abstract ';
/**
* The string used when writing the 'const' modifier.
*/
static const String CONST_MODIFIER = 'const ';
/**
* A utility class used to help build the source code.
*/
final CorrectionUtils utils;
// /**
// * The string used when writing the 'final' modifier.
// */
// static const String FINAL_MODIFIER = 'final ';
//
// /**
// * The string used when writing the 'static' modifier.
// */
// static const String STATIC_MODIFIER = 'static ';
/**
* Initialize a newly created builder to build a source edit.
*/
DartEditBuilderImpl(
DartFileEditBuilderImpl sourceFileEditBuilder, int offset, int length)
: utils = sourceFileEditBuilder.utils,
super(sourceFileEditBuilder, offset, length);
DartFileEditBuilderImpl get dartFileEditBuilder => fileEditBuilder;
@override
void writeClassDeclaration(String name, {Iterator<DartType> interfaces,
bool isAbstract: false, void memberWriter(), Iterator<DartType> mixins, DartType superclass}) {
// TODO(brianwilkerson) Add support for type parameters
// Map<String, DartType>, List<TypeParameter>?
//
// TODO(brianwilkerson) Make additional optional parameters visible in the
// public API.
if (isAbstract) {
write(ABSTRACT_MODIFIER);
}
write('class ');
addLinkedEdit(DartEditBuilder.NAME_GROUP_ID, (LinkedEditBuilder builder) {
write(name);
});
if (superclass != null) {
write(' extends ');
writeType(superclass, groupName: DartEditBuilder.SUPERCLASS_GROUP_ID);
}
writeTypes(mixins, prefix: ' with ');
writeTypes(interfaces, prefix: ' implements ');
writeln(' {');
if (memberWriter != null) {
memberWriter();
}
write('}');
}
/**
* Write the code for a comma-separated list of [types], optionally prefixed
* by a [prefix]. If the list of [types] is `null` or does not return any
* types, then nothing will be written.
*/
void writeTypes(Iterator<DartType> types, {String prefix}) {
if (types == null) {
return;
}
bool first = true;
while (types.moveNext()) {
if (first) {
if (prefix != null) {
write(prefix);
}
first = false;
} else {
write(', ');
}
writeType(types.current);
}
}
void writeConstructorDeclaration(ClassElement classElement,
{ArgumentList argumentList, SimpleIdentifier constructorName,
bool isConst: false}) {
// TODO(brianwilkerson) Clean up the API and add it to the public API.
//
// TODO(brianwilkerson) Support passing a list of final fields rather than
// an argument list.
if (isConst) {
write(CONST_MODIFIER);
}
write(classElement.name);
write('.');
if (constructorName != null) {
addLinkedEdit(DartEditBuilder.NAME_GROUP_ID, (LinkedEditBuilder builder) {
write(constructorName.name);
});
CompilationUnit unit = constructorName
.getAncestor((AstNode node) => node is CompilationUnit);
if (unit != null) {
CompilationUnitElement element = unit.element;
if (element != null) {
String referenceFile = element.source.fullName;
if (referenceFile == dartFileEditBuilder.fileEdit.file) {
dartFileEditBuilder.addLinkedPosition(constructorName.offset,
constructorName.length, DartEditBuilder.NAME_GROUP_ID);
}
}
}
}
if (argumentList != null) {
writeParametersMatchingArguments(argumentList);
} else {
write('()');
}
writeln(' {');
write(' }');
}
@override
void writeOverrideOfInheritedMember(ExecutableElement member) {
// prepare environment
String prefix = utils.getIndent(1);
// may be property
String prefix2 = utils.getIndent(2);
ElementKind elementKind = member.kind;
bool isGetter = elementKind == ElementKind.GETTER;
bool isSetter = elementKind == ElementKind.SETTER;
bool isMethod = elementKind == ElementKind.METHOD;
bool isOperator = isMethod && (member as MethodElement).isOperator;
write(prefix);
if (isGetter) {
writeln('// TODO: implement ${member.displayName}');
write(prefix);
}
// @override
writeln('@override');
write(prefix);
// return type
// REVIEW: Added groupId
bool shouldReturn = writeType(member.type.returnType,
groupName: DartEditBuilder.RETURN_TYPE_GROUP_ID);
write(' ');
if (isGetter) {
write('get ');
} else if (isSetter) {
write('set ');
} else if (isOperator) {
write('operator ');
}
// name
write(member.displayName);
// parameters + body
if (isGetter) {
writeln(' => null;');
} else {
List<ParameterElement> parameters = member.parameters;
writeParameters(parameters);
writeln(' {');
// TO-DO
write(prefix2);
writeln('// TODO: implement ${member.displayName}');
// REVIEW: Added return statement.
if (shouldReturn) {
write(prefix2);
writeln('return null;');
}
// close method
write(prefix);
writeln('}');
}
}
@override
void writeParameters(Iterable<ParameterElement> parameters) {
write('(');
bool sawNamed = false;
bool sawPositional = false;
for (int i = 0; i < parameters.length; i++) {
ParameterElement parameter = parameters.elementAt(i);
if (i > 0) {
write(', ');
}
// may be optional
ParameterKind parameterKind = parameter.parameterKind;
if (parameterKind == ParameterKind.NAMED) {
if (!sawNamed) {
write('{');
sawNamed = true;
}
}
if (parameterKind == ParameterKind.POSITIONAL) {
if (!sawPositional) {
write('[');
sawPositional = true;
}
}
// parameter
writeParameterSource(parameter.type, parameter.name);
// default value
String defaultCode = parameter.defaultValueCode;
if (defaultCode != null) {
if (sawPositional) {
write(' = ');
} else {
write(': ');
}
write(defaultCode);
}
}
// close parameters
if (sawNamed) {
write('}');
}
if (sawPositional) {
write(']');
}
write(')');
}
@override
void writeParametersMatchingArguments(ArgumentList arguments) {
Set<String> excluded = new Set();
bool namedFound = false;
write('(');
List<Expression> argumentList = arguments.arguments;
for (int i = 0; i < argumentList.length; i++) {
Expression argument = argumentList[i];
DartType type = argument.bestType;
List<String> suggestions =
_getParameterNameSuggestions(excluded, type, argument, i);
String favorite = suggestions[0];
// append separator
if (i > 0) {
write(', ');
}
if (argument is NamedExpression) {
if (!namedFound) {
namedFound = true;
write('[');
}
favorite = argument.name.label.name;
}
// append type name
writeType(type, addSupertypeProposals: true, groupName: 'TYPE$i');
write(' ');
// append parameter name
excluded.add(favorite);
addLinkedEdit('ARG$i', (LinkedEditBuilder builder) {
builder.write(favorite);
builder.addSuggestions(LinkedEditSuggestionKind.PARAMETER, suggestions);
});
}
if (namedFound) {
write(']');
}
write(')');
}
@override
void writeParameterSource(DartType type, String name) {
String parameterSource = utils.getParameterSource(
type, name, dartFileEditBuilder.librariesToImport);
write(parameterSource);
}
@override
bool writeType(DartType type, {bool addSupertypeProposals: false,
String groupName, bool required: false}) {
if (type != null && !type.isDynamic) {
String typeSource =
utils.getTypeSource(type, dartFileEditBuilder.librariesToImport);
if (groupName != null) {
addLinkedEdit(groupName, (LinkedEditBuilder builder) {
write(typeSource);
if (addSupertypeProposals) {
_addSuperTypeProposals(builder, type, new Set<DartType>());
}
});
} else {
write(typeSource);
}
return true;
} else if (required) {
write('var');
}
return false;
}
void _addSuperTypeProposals(
LinkedEditBuilder builder, DartType type, Set<DartType> alreadyAdded) {
if (type != null &&
type.element is ClassElement &&
alreadyAdded.add(type)) {
ClassElement element = type.element as ClassElement;
builder.addSuggestion(LinkedEditSuggestionKind.TYPE, element.name);
_addSuperTypeProposals(builder, element.supertype, alreadyAdded);
for (InterfaceType interfaceType in element.interfaces) {
_addSuperTypeProposals(builder, interfaceType, alreadyAdded);
}
}
}
/**
* Return a list containing the suggested names for a parmeter with the given
* [type] whose value in one location is computed by the given [expression].
* The list will not contain any names in the set of [excluded] names. The
* [index] is the index of the argument, used to create a name if no better
* name could be created. The first name in the list will be the best name.
*/
List<String> _getParameterNameSuggestions(
Set<String> excluded, DartType type, Expression expression, int index) {
List<String> suggestions =
getVariableNameSuggestionsForExpression(type, expression, excluded);
if (suggestions.length != 0) {
return suggestions;
}
return <String>['arg$index'];
}
}
/**
* A [FileEditBuilder] used to build edits for Dart files.
*/
class DartFileEditBuilderImpl extends FileEditBuilderImpl
implements DartFileEditBuilder {
/**
* The compilation unit to which the code will be added.
*/
CompilationUnit unit;
/**
* A utility class used to help build the source code.
*/
CorrectionUtils utils;
/**
* A set containing the elements of the libraries that need to be imported in
* order to make visible the names used in generated code.
*/
Set<LibraryElement> librariesToImport = new Set<LibraryElement>();
/**
* Initialize a newly created builder to build a source file edit within the
* change being built by the given [changeBuilder]. The file being edited has
* the given [source] and [timeStamp].
*/
DartFileEditBuilderImpl(
DartChangeBuilderImpl changeBuilder, Source source, int timeStamp)
: super(changeBuilder, source, timeStamp) {
AnalysisContext context = changeBuilder.context;
List<Source> librariesContaining = context.getLibrariesContaining(source);
if (librariesContaining.length < 1) {
throw new StateError('Cannot build edits for ${source.fullName}');
}
unit = context.resolveCompilationUnit2(source, librariesContaining[0]);
utils = new CorrectionUtils(unit);
}
@override
DartEditBuilderImpl createEditBuilder(int offset, int length) {
return new DartEditBuilderImpl(this, offset, length);
}
}

View file

@ -0,0 +1,123 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library analysis_server.utilities.change_builder_core;
import 'package:analysis_server/src/utilities/change_builder_core.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analyzer/src/generated/source.dart';
/**
* A builder used to build a [SourceChange].
*
* Clients are not expected to subtype this class.
*/
abstract class ChangeBuilder {
/**
* Initialize a newly created change builder.
*/
factory ChangeBuilder() = ChangeBuilderImpl;
/**
* Return the source change that was built.
*/
SourceChange get sourceChange;
/**
* Use the [buildFileEdit] function to create a collection of edits to the
* given [source]. The edits will be added to the source change that is being
* built. The [timeStamp] is the time at which the [source] was last modified
* and is used by clients to ensure that it is safe to apply the edits.
*/
void addFileEdit(Source source, int timeStamp,
void buildFileEdit(FileEditBuilder builder));
}
/**
* A builder used to build a [SourceEdit] as part of a [SourceFileEdit].
*
* Clients are not expected to subtype this class.
*/
abstract class EditBuilder {
/**
* Add a region of text that is part of the linked edit group with the given
* [groupName]. The [buildLinkedEdit] function is used to write the content of
* the region of text and to add suggestions for other possible values for
* that region.
*/
void addLinkedEdit(
String groupName, void buildLinkedEdit(LinkedEditBuilder builder));
/**
* Add the given [string] to the content of the current edit.
*/
void write(String string);
/**
* Add the given [string] to the content of the current edit and then add an
* end-of-line marker.
*/
void writeln([String string]);
}
/**
* A builder used to build a [SourceFileEdit] within a [SourceChange].
*
* Clients are not expected to subtype this class.
*/
abstract class FileEditBuilder {
/**
* Add an insertion of text at the given [offset]. The [offset] is relative to
* the original source. The [buildEdit] function is used to write the text to
* be inserted. This is fully equivalent to
*
* addReplacement(offset, 0, buildEdit);
*/
void addInsertion(int offset, void buildEdit(EditBuilder builder));
/**
* Add the region of text starting at the given [offset] and continuing for
* the given [length] to the linked edit group with the given [groupName].
* The [offset] is relative to the original source. This is typically used to
* include pre-existing regions of text in a group.
*/
void addLinkedPosition(int offset, int length, String groupName);
/**
* Add a replacement of text starting at the given [offset] and continuing for
* the given [length]. The [offset] is relative to the original source. The
* [buildEdit] function is used to write the text that will replace the
* specified region.
*/
void addReplacement(
int offset, int length, void buildEdit(EditBuilder builder));
}
/**
* A builder used to build a [LinkedEdit] region within an edit.
*
* Clients are not expected to subtype this class.
*/
abstract class LinkedEditBuilder {
/**
* Add the given [value] as a suggestion with the given [kind].
*/
void addSuggestion(LinkedEditSuggestionKind kind, String value);
/**
* Add each of the given [values] as a suggestion with the given [kind].
*/
void addSuggestions(LinkedEditSuggestionKind kind, Iterable<String> values);
/**
* Add the given [string] to the content of the current edit.
*/
void write(String string);
/**
* Add the given [string] to the content of the current edit and then add an
* end-of-line marker.
*/
void writeln([String string]);
}

View file

@ -0,0 +1,98 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library analysis_server.utilities.change_builder_dart;
import 'package:analysis_server/src/utilities/change_builder_dart.dart';
import 'package:analysis_server/utilities/change_builder_core.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
/**
* A [ChangeBuilder] used to build changes in Dart files.
*
* Clients are not expected to subtype this class.
*/
abstract class DartChangeBuilder extends ChangeBuilder {
/**
* Initialize a newly created change builder.
*/
factory DartChangeBuilder(AnalysisContext context) = DartChangeBuilderImpl;
}
/**
* An [EditBuilder] used to build edits in Dart files.
*
* Clients are not expected to subtype this class.
*/
abstract class DartEditBuilder extends EditBuilder {
/**
* The group-id used for the name of a declaration.
*/
static const String NAME_GROUP_ID = 'NAME';
/**
* The group-id used for the return type of a function, getter or method.
*/
static const String RETURN_TYPE_GROUP_ID = 'RETURN_TYPE';
/**
* The group-id used for the name of the superclass in a class declaration.
*/
static const String SUPERCLASS_GROUP_ID = 'SUPERCLASS';
/**
* Write the code for a declaration of a class with the given [name]. If
* [isAbstract] is `true`, then the class will be abstract. If a [superclass]
* is given then it will be the superclass of the class.
*/
void writeClassDeclaration(String name,
{bool isAbstract: false, DartType superclass});
/**
* Append a placeholder for an override of an inherited [member].
*/
void writeOverrideOfInheritedMember(ExecutableElement member);
/**
* Write the code for a list of [parameters], including the surrounding
* parentheses.
*/
void writeParameters(Iterable<ParameterElement> parameters);
/**
* Write the code for a list of parameters that would match the given list of
* [arguments], including the surrounding parentheses.
*/
void writeParametersMatchingArguments(ArgumentList arguments);
/**
* Write the code for a single parameter with the given [type] and [name].
* The [type] can be `null` if no type is to be specified for the parameter.
*/
void writeParameterSource(DartType type, String name);
/**
* Write the code for a type annotation for the given [type]. If the [type] is
* either `null` or represents the type 'dynamic', then the behavior depends
* on whether a type is [required]. If [required] is `true`, then 'var' will
* be written; otherwise, nothing is written.
*
* If the [groupName] is not `null`, then the name of the type (including type
* parameters) will be included as a region in the linked edit group with that
* name. If the [groupName] is not `null` and [addSupertypeProposals] is
* `true`, then all of the supertypes of the [type] will be added as
* suggestions for alternatives to the type name.
*/
bool writeType(DartType type,
{bool addSupertypeProposals: false, String groupName, bool required: false});
}
/**
* A [FileEditBuilder] used to build edits for Dart files.
*
* Clients are not expected to subtype this class.
*/
abstract class DartFileEditBuilder extends FileEditBuilder {}

View file

@ -0,0 +1,19 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library test.src;
import 'package:unittest/unittest.dart';
import 'utilities/test_all.dart' as utilities_all;
/**
* Utility for manually running all tests.
*/
main() {
groupSep = ' | ';
group('analysis_server', () {
utilities_all.main();
});
}

View file

@ -0,0 +1,253 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library analysis_server.test.src.utilities.change_builder_core_test;
import 'package:analysis_server/src/utilities/change_builder_core.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/utilities/change_builder_core.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
import '../../domain_execution_test.dart';
main() {
groupSep = ' | ';
defineReflectiveTests(ChangeBuilderImplTest);
defineReflectiveTests(EditBuilderImplTest);
defineReflectiveTests(FileEditBuilderImplTest);
defineReflectiveTests(LinkedEditBuilderImplTest);
}
@reflectiveTest
class ChangeBuilderImplTest {
void test_createFileEditBuilder() {
ChangeBuilderImpl builder = new ChangeBuilderImpl();
TestSource source = new TestSource('/test.dart');
int timeStamp = 54;
FileEditBuilderImpl fileEditBuilder = builder.createFileEditBuilder(source, timeStamp);
expect(fileEditBuilder, new isInstanceOf<FileEditBuilder>());
SourceFileEdit fileEdit = fileEditBuilder.fileEdit;
expect(fileEdit.file, source.fullName);
expect(fileEdit.fileStamp, timeStamp);
}
void test_getLinkedEditGroup() {
ChangeBuilderImpl builder = new ChangeBuilderImpl();
LinkedEditGroup group = builder.getLinkedEditGroup('a');
expect(identical(builder.getLinkedEditGroup('b'), group), isFalse);
expect(identical(builder.getLinkedEditGroup('a'), group), isTrue);
}
void test_sourceChange_noChanges() {
ChangeBuilderImpl builder = new ChangeBuilderImpl();
SourceChange sourceChange = builder.sourceChange;
expect(sourceChange, isNotNull);
expect(sourceChange.edits, isEmpty);
expect(sourceChange.linkedEditGroups, isEmpty);
expect(sourceChange.message, isEmpty);
expect(sourceChange.selection, isNull);
}
void test_sourceChange_oneChange() {
ChangeBuilderImpl builder = new ChangeBuilderImpl();
TestSource source = new TestSource('/test.dart');
builder.addFileEdit(source, 0, (FileEditBuilder builder) {});
builder.getLinkedEditGroup('a');
SourceChange sourceChange = builder.sourceChange;
expect(sourceChange, isNotNull);
expect(sourceChange.edits, hasLength(1));
expect(sourceChange.linkedEditGroups, hasLength(1));
expect(sourceChange.message, isEmpty);
expect(sourceChange.selection, isNull);
}
}
@reflectiveTest
class EditBuilderImplTest {
TestSource source = new TestSource('/test.dart');
void test_addLinkedEdit() {
ChangeBuilderImpl builder = new ChangeBuilderImpl();
int offset = 10;
String text = 'content';
builder.addFileEdit(source, 0, (FileEditBuilderImpl builder) {
builder.addInsertion(10, (EditBuilderImpl builder) {
builder.addLinkedEdit('a', (LinkedEditBuilder builder) {
builder.write(text);
});
SourceEdit sourceEdit = builder.sourceEdit;
expect(sourceEdit.replacement, text);
});
});
SourceChange sourceChange = builder.sourceChange;
expect(sourceChange, isNotNull);
List<LinkedEditGroup> groups = sourceChange.linkedEditGroups;
expect(groups, hasLength(1));
LinkedEditGroup group = groups[0];
expect(group, isNotNull);
expect(group.length, text.length);
List<Position> positions = group.positions;
expect(positions, hasLength(1));
expect(positions[0].offset, offset);
}
void test_createLinkedEditBuilder() {
ChangeBuilderImpl builder = new ChangeBuilderImpl();
builder.addFileEdit(source, 0, (FileEditBuilderImpl builder) {
builder.addInsertion(10, (EditBuilderImpl builder) {
LinkedEditBuilderImpl linkBuilder = builder.createLinkedEditBuilder();
expect(linkBuilder, new isInstanceOf<LinkedEditBuilder>());
});
});
}
void test_write() {
ChangeBuilderImpl builder = new ChangeBuilderImpl();
int timeStamp = 93;
int offset = 10;
String text = 'write';
builder.addFileEdit(source, timeStamp, (FileEditBuilderImpl builder) {
builder.addInsertion(offset, (EditBuilderImpl builder) {
builder.write(text);
});
});
SourceChange sourceChange = builder.sourceChange;
expect(sourceChange, isNotNull);
List<SourceFileEdit> fileEdits = sourceChange.edits;
expect(fileEdits, hasLength(1));
SourceFileEdit fileEdit = fileEdits[0];
expect(fileEdit, isNotNull);
expect(fileEdit.file, source.fullName);
expect(fileEdit.fileStamp, timeStamp);
List<SourceEdit> edits = fileEdit.edits;
expect(edits, hasLength(1));
SourceEdit edit = edits[0];
expect(edit, isNotNull);
expect(edit.offset, offset);
expect(edit.length, 0);
expect(edit.replacement, text);
}
void test_writeln() {
ChangeBuilderImpl builder = new ChangeBuilderImpl();
int timeStamp = 39;
int offset = 52;
int length = 12;
String text = 'writeln';
builder.addFileEdit(source, timeStamp, (FileEditBuilderImpl builder) {
builder.addReplacement(offset, length, (EditBuilderImpl builder) {
builder.writeln(text);
});
});
SourceChange sourceChange = builder.sourceChange;
expect(sourceChange, isNotNull);
List<SourceFileEdit> fileEdits = sourceChange.edits;
expect(fileEdits, hasLength(1));
SourceFileEdit fileEdit = fileEdits[0];
expect(fileEdit, isNotNull);
expect(fileEdit.file, source.fullName);
expect(fileEdit.fileStamp, timeStamp);
List<SourceEdit> edits = fileEdit.edits;
expect(edits, hasLength(1));
SourceEdit edit = edits[0];
expect(edit, isNotNull);
expect(edit.offset, offset);
expect(edit.length, length);
expect(edit.replacement == '$text\n' || edit.replacement == '$text\r\n', isTrue);
}
}
@reflectiveTest
class FileEditBuilderImplTest {
TestSource source = new TestSource('/test.dart');
void test_addInsertion() {
ChangeBuilderImpl builder = new ChangeBuilderImpl();
builder.addFileEdit(source, 0, (FileEditBuilderImpl builder) {
builder.addInsertion(10, (EditBuilderImpl builder) {
expect(builder, isNotNull);
});
});
}
void test_addLinkedPosition() {
ChangeBuilderImpl changeBuilder = new ChangeBuilderImpl();
String groupName = 'a';
changeBuilder.addFileEdit(source, 0, (FileEditBuilderImpl builder) {
builder.addLinkedPosition(3, 6, groupName);
});
LinkedEditGroup group = changeBuilder.getLinkedEditGroup(groupName);
List<Position> positions = group.positions;
expect(positions, hasLength(1));
Position position = positions[0];
expect(position.file, source.fullName);
expect(position.offset, 3);
expect(group.length, 6);
}
void test_addReplacement() {
ChangeBuilderImpl builder = new ChangeBuilderImpl();
builder.addFileEdit(source, 0, (FileEditBuilderImpl builder) {
builder.addReplacement(4, 5, (EditBuilderImpl builder) {
expect(builder, isNotNull);
});
});
}
void test_createEditBuilder() {
ChangeBuilderImpl builder = new ChangeBuilderImpl();
builder.addFileEdit(source, 0, (FileEditBuilderImpl builder) {
int offset = 4;
int length = 5;
EditBuilderImpl editBuilder = builder.createEditBuilder(offset, length);
expect(editBuilder, new isInstanceOf<EditBuilder>());
SourceEdit sourceEdit = editBuilder.sourceEdit;
expect(sourceEdit.length, length);
expect(sourceEdit.offset, offset);
expect(sourceEdit.replacement, isEmpty);
});
}
}
@reflectiveTest
class LinkedEditBuilderImplTest {
TestSource source = new TestSource('/test.dart');
void test_addSuggestion() {
String groupName = 'a';
ChangeBuilderImpl builder = new ChangeBuilderImpl();
builder.addFileEdit(source, 0, (FileEditBuilderImpl builder) {
builder.addInsertion(10, (EditBuilderImpl builder) {
builder.addLinkedEdit(groupName, (LinkedEditBuilderImpl builder) {
builder.addSuggestion(LinkedEditSuggestionKind.TYPE, 'A');
});
});
});
LinkedEditGroup group = builder.getLinkedEditGroup(groupName);
expect(group.suggestions, hasLength(1));
}
void test_addSuggestions() {
String groupName = 'a';
ChangeBuilderImpl builder = new ChangeBuilderImpl();
builder.addFileEdit(source, 0, (FileEditBuilderImpl builder) {
builder.addInsertion(10, (EditBuilderImpl builder) {
builder.addLinkedEdit(groupName, (LinkedEditBuilderImpl builder) {
builder.addSuggestions(LinkedEditSuggestionKind.TYPE, ['A', 'B']);
});
});
});
LinkedEditGroup group = builder.getLinkedEditGroup(groupName);
expect(group.suggestions, hasLength(2));
}
}

View file

@ -0,0 +1,438 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library analysis_server.test.src.utilities.change_builder_dart_test;
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/utilities/change_builder_core.dart';
import 'package:analysis_server/src/utilities/change_builder_dart.dart';
import 'package:analysis_server/utilities/change_builder_core.dart';
import 'package:analysis_server/utilities/change_builder_dart.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
import '../../abstract_context.dart';
import '../../domain_execution_test.dart';
main() {
groupSep = ' | ';
defineReflectiveTests(DartChangeBuilderImplTest);
defineReflectiveTests(DartEditBuilderImplTest);
defineReflectiveTests(DartFileEditBuilderImplTest);
}
@reflectiveTest
class DartChangeBuilderImplTest extends AbstractContextTest {
void test_createFileEditBuilder() {
Source source = addSource('/test.dart', 'library test;');
resolveLibraryUnit(source);
int timeStamp = 54;
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
DartFileEditBuilderImpl fileEditBuilder =
builder.createFileEditBuilder(source, timeStamp);
expect(fileEditBuilder, new isInstanceOf<DartFileEditBuilder>());
SourceFileEdit fileEdit = fileEditBuilder.fileEdit;
expect(fileEdit.file, source.fullName);
expect(fileEdit.fileStamp, timeStamp);
}
}
@reflectiveTest
class DartEditBuilderImplTest extends AbstractContextTest {
SourceEdit getEdit(DartChangeBuilderImpl builder) {
SourceChange sourceChange = builder.sourceChange;
expect(sourceChange, isNotNull);
List<SourceFileEdit> fileEdits = sourceChange.edits;
expect(fileEdits, hasLength(1));
SourceFileEdit fileEdit = fileEdits[0];
expect(fileEdit, isNotNull);
List<SourceEdit> edits = fileEdit.edits;
expect(edits, hasLength(1));
return edits[0];
}
void test_writeClassDeclaration_isAbstract() {
Source source = addSource('/test.dart', '');
resolveLibraryUnit(source);
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(0, (DartEditBuilder builder) {
builder.writeClassDeclaration('C', isAbstract: true);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('abstract class C { }'));
}
void test_writeClassDeclaration_nameOnly() {
Source source = addSource('/test.dart', '');
resolveLibraryUnit(source);
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(0, (DartEditBuilder builder) {
builder.writeClassDeclaration('C');
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('class C { }'));
List<LinkedEditGroup> linkedEditGroups =
builder.sourceChange.linkedEditGroups;
expect(linkedEditGroups, hasLength(1));
LinkedEditGroup group = linkedEditGroups[0];
expect(group.length, 1);
expect(group.positions, hasLength(1));
}
void test_writeClassDeclaration_superclass() {
Source source = addSource('/test.dart', 'class B {}');
CompilationUnit unit = resolveLibraryUnit(source);
ClassDeclaration declaration = unit.declarations[0];
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(0, (DartEditBuilder builder) {
builder.writeClassDeclaration('C',
superclass: declaration.element.type);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('class C extends B { }'));
}
void test_writeOverrideOfInheritedMember() {
String content = '''
class A {
A add(A a) => null;
}
class B extends A {
}''';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
ClassDeclaration declaration = unit.declarations[0];
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeOverrideOfInheritedMember(declaration.element.methods[0]);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('''
@override
A add(A a) {
// TODO: implement add
return null;
}'''));
}
void test_writeParameters_named() {
String content = 'f(int i, {String s}) {}';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
FunctionDeclaration f = unit.declarations[0];
FormalParameterList parameters = f.functionExpression.parameters;
Iterable elements = parameters.parameters
.map((FormalParameter parameter) => parameter.element);
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeParameters(elements);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('(int i, {String s})'));
}
void test_writeParameters_positional() {
String content = 'f(int i, [String s]) {}';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
FunctionDeclaration f = unit.declarations[0];
FormalParameterList parameters = f.functionExpression.parameters;
Iterable elements = parameters.parameters
.map((FormalParameter parameter) => parameter.element);
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeParameters(elements);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('(int i, [String s])'));
}
void test_writeParameters_required() {
String content = 'f(int i, String s) {}';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
FunctionDeclaration f = unit.declarations[0];
FormalParameterList parameters = f.functionExpression.parameters;
Iterable elements = parameters.parameters
.map((FormalParameter parameter) => parameter.element);
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeParameters(elements);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('(int i, String s)'));
}
void test_writeParametersMatchingArguments_named() {
String content = '''
f(int i, String s) {
g(s, index: i);
}''';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
FunctionDeclaration f = unit.declarations[0];
BlockFunctionBody body = f.functionExpression.body;
ExpressionStatement statement = body.block.statements[0];
MethodInvocation invocation = statement.expression;
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeParametersMatchingArguments(invocation.argumentList);
});
});
SourceEdit edit = getEdit(builder);
expect(
edit.replacement, equalsIgnoringWhitespace('(String s, [int index])'));
}
void test_writeParametersMatchingArguments_required() {
String content = '''
f(int i, String s) {
g(s, i);
}''';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
FunctionDeclaration f = unit.declarations[0];
BlockFunctionBody body = f.functionExpression.body;
ExpressionStatement statement = body.block.statements[0];
MethodInvocation invocation = statement.expression;
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeParametersMatchingArguments(invocation.argumentList);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('(String s, int i)'));
}
void test_writeParameterSource() {
String content = 'class A {}';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
ClassDeclaration classA = unit.declarations[0];
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeParameterSource(classA.element.type, 'a');
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('A a'));
}
void test_writeType_dymanic() {
String content = 'class A {}';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeType(unit.element.context.typeProvider.dynamicType);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace(''));
}
void test_writeType_genericType() {
String content = 'class A {} class B<E> {}';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
ClassDeclaration classA = unit.declarations[0];
ClassDeclaration classB = unit.declarations[1];
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder
.writeType(classB.element.type.substitute4([classA.element.type]));
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('B<A>'));
}
void test_writeType_groupName() {
String content = 'class A {} class B extends A {} class C extends B {}';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
ClassDeclaration classC = unit.declarations[2];
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeType(classC.element.type, groupName: 'type');
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('C'));
List<LinkedEditGroup> linkedEditGroups =
builder.sourceChange.linkedEditGroups;
expect(linkedEditGroups, hasLength(1));
LinkedEditGroup group = linkedEditGroups[0];
expect(group, isNotNull);
}
void test_writeType_groupName_addSupertypeProposals() {
String content = 'class A {} class B extends A {} class C extends B {}';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
ClassDeclaration classC = unit.declarations[2];
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeType(classC.element.type,
addSupertypeProposals: true, groupName: 'type');
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('C'));
List<LinkedEditGroup> linkedEditGroups =
builder.sourceChange.linkedEditGroups;
expect(linkedEditGroups, hasLength(1));
LinkedEditGroup group = linkedEditGroups[0];
List<LinkedEditSuggestion> suggestions = group.suggestions;
expect(suggestions, hasLength(4));
Iterable<String> values = suggestions
.map((LinkedEditSuggestion suggestion) {
expect(suggestion.kind, LinkedEditSuggestionKind.TYPE);
return suggestion.value;
});
expect(values, contains('Object'));
expect(values, contains('A'));
expect(values, contains('B'));
expect(values, contains('C'));
}
void test_writeType_null() {
String content = 'class A {}';
Source source = addSource('/test.dart', content);
resolveLibraryUnit(source);
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeType(null);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace(''));
}
void test_writeType_required_dymanic() {
String content = 'class A {}';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeType(unit.element.context.typeProvider.dynamicType,
required: true);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('var'));
}
void test_writeType_required_notNull() {
String content = 'class A {}';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
ClassDeclaration classA = unit.declarations[0];
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeType(classA.element.type, required: true);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('A'));
}
void test_writeType_required_null() {
String content = 'class A {}';
Source source = addSource('/test.dart', content);
resolveLibraryUnit(source);
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeType(null, required: true);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('var'));
}
void test_writeType_simpleType() {
String content = 'class A {}';
Source source = addSource('/test.dart', content);
CompilationUnit unit = resolveLibraryUnit(source);
ClassDeclaration classA = unit.declarations[0];
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, 1, (DartFileEditBuilderImpl builder) {
builder.addInsertion(content.length - 1, (DartEditBuilder builder) {
builder.writeType(classA.element.type);
});
});
SourceEdit edit = getEdit(builder);
expect(edit.replacement, equalsIgnoringWhitespace('A'));
}
}
@reflectiveTest
class DartFileEditBuilderImplTest extends AbstractContextTest {
void test_createEditBuilder() {
Source source = addSource('/test.dart', 'library test;');
resolveLibraryUnit(source);
int timeStamp = 65;
DartChangeBuilderImpl builder = new DartChangeBuilderImpl(context);
builder.addFileEdit(source, timeStamp, (DartFileEditBuilderImpl builder) {
int offset = 4;
int length = 5;
DartEditBuilderImpl editBuilder =
builder.createEditBuilder(offset, length);
expect(editBuilder, new isInstanceOf<DartEditBuilder>());
SourceEdit sourceEdit = editBuilder.sourceEdit;
expect(sourceEdit.length, length);
expect(sourceEdit.offset, offset);
expect(sourceEdit.replacement, isEmpty);
});
}
}

View file

@ -0,0 +1,17 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library test.services;
import 'package:unittest/unittest.dart';
import 'change_builder_core_test.dart' as change_builder_core_test;
import 'change_builder_dart_test.dart' as change_builder_dart_test;
/// Utility for manually running all tests.
main() {
groupSep = ' | ';
change_builder_core_test.main();
change_builder_dart_test.main();
}

View file

@ -20,6 +20,7 @@ import 'search/test_all.dart' as search_all;
import 'services/test_all.dart' as services_all;
import 'socket_server_test.dart' as socket_server_test;
import 'source/test_all.dart' as source_all;
import 'src/test_all.dart' as src_all;
/**
* Utility for manually running all tests.
@ -43,5 +44,6 @@ main() {
services_all.main();
socket_server_test.main();
source_all.main();
src_all.main();
});
}