0fcd1a6fa1
Change-Id: I70157caf90c0955c2eb8426f5721ba4ed527eb76 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/427900 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Auto-Submit: Paul Berry <paulberry@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
590 lines
11 KiB
Dart
590 lines
11 KiB
Dart
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
import 'package:_fe_analyzer_shared/src/testing/annotated_code_helper.dart';
|
|
import 'package:_fe_analyzer_shared/src/testing/id.dart';
|
|
import 'package:_fe_analyzer_shared/src/testing/id_generation.dart';
|
|
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
|
|
import 'package:_fe_analyzer_shared/src/testing/features.dart';
|
|
|
|
const List<String> markers = ['a', 'b', 'c'];
|
|
final Uri mainUri = Uri.parse('memory:main.dart');
|
|
|
|
main() {
|
|
testString('/*test*/');
|
|
testString('''
|
|
some code/*test*/some more code
|
|
''');
|
|
testString('/*a.test*/');
|
|
testString('''
|
|
some code/*a.test*/some more code
|
|
''');
|
|
testString('/*a|b.test*/');
|
|
testString('''
|
|
some code/*a|b.test*/some more code
|
|
''');
|
|
testString('/*a|b|c.test*/', expectedResult: '/*test*/');
|
|
testString(
|
|
'''
|
|
some code/*a|b|c.test*/some more code
|
|
''',
|
|
expectedResult: '''
|
|
some code/*test*/some more code
|
|
''',
|
|
);
|
|
testString('/*a.test1*//*b.test2*//*c.test3*/');
|
|
testString('/*b.test2*//*a.test1*//*c.test3*/');
|
|
testString('/*a.test1*//*c.test3*//*b.test2*/');
|
|
|
|
testString(
|
|
'some code',
|
|
actualData: {
|
|
'a': {new NodeId(0, IdKind.node): 'test'},
|
|
'b': {new NodeId(0, IdKind.node): 'test'},
|
|
'c': {new NodeId(0, IdKind.node): 'test'},
|
|
},
|
|
expectedResult: '/*test*/some code',
|
|
);
|
|
|
|
testString(
|
|
'some code',
|
|
actualData: {
|
|
'a': {new NodeId(4, IdKind.node): 'test'},
|
|
'b': {new NodeId(4, IdKind.node): 'test'},
|
|
'c': {new NodeId(4, IdKind.node): 'test'},
|
|
},
|
|
expectedResult: 'some/*test*/ code',
|
|
);
|
|
|
|
testString(
|
|
'some code',
|
|
actualData: {
|
|
'a': {new NodeId(0, IdKind.node): 'test'},
|
|
'b': {new NodeId(0, IdKind.node): 'test'},
|
|
},
|
|
expectedResult: '/*a|b.test*/some code',
|
|
);
|
|
|
|
testString(
|
|
'some code',
|
|
actualData: {
|
|
'a': {new NodeId(0, IdKind.node): 'test'},
|
|
},
|
|
expectedResult: '/*a.test*/some code',
|
|
);
|
|
|
|
testString(
|
|
'',
|
|
actualData: {
|
|
'a': {new NodeId(0, IdKind.node): 'test1'},
|
|
'b': {new NodeId(0, IdKind.node): 'test2'},
|
|
'c': {new NodeId(0, IdKind.node): 'test3'},
|
|
},
|
|
expectedResult: '/*a.test1*//*b.test2*//*c.test3*/',
|
|
);
|
|
testString(
|
|
'some code/*test*/some more code',
|
|
actualData: {
|
|
'a': {new NodeId(9, IdKind.node): 'test1'},
|
|
},
|
|
expectedResult: 'some code/*a.test1*//*b|c.test*/some more code',
|
|
);
|
|
|
|
testString(
|
|
'some codesome more code',
|
|
actualData: {
|
|
'a': {new NodeId(9, IdKind.node): ''},
|
|
'b': {new NodeId(9, IdKind.node): ''},
|
|
'c': {new NodeId(9, IdKind.node): ''},
|
|
},
|
|
expectedResult: 'some codesome more code',
|
|
);
|
|
|
|
testString(
|
|
'some codesome more code',
|
|
actualData: {
|
|
'a': {new NodeId(9, IdKind.node): ''},
|
|
'b': {new NodeId(9, IdKind.node): ''},
|
|
},
|
|
expectedResult: 'some codesome more code',
|
|
);
|
|
|
|
testString(
|
|
'some codesome more code',
|
|
actualData: {
|
|
'a': {new NodeId(9, IdKind.node): ''},
|
|
},
|
|
expectedResult: 'some codesome more code',
|
|
);
|
|
|
|
testString('''
|
|
some code
|
|
/*member: memberName:test*/
|
|
some more code
|
|
''');
|
|
|
|
testString(
|
|
'''
|
|
some code
|
|
/*member: memberName:test*/
|
|
some more code
|
|
''',
|
|
actualData: {
|
|
'a': {new MemberId('memberName'): 'test1'},
|
|
},
|
|
expectedResult: '''
|
|
some code
|
|
/*a.member: memberName:test1*/
|
|
/*b|c.member: memberName:test*/
|
|
some more code
|
|
''',
|
|
);
|
|
|
|
testString(
|
|
'''some code
|
|
/*a.member: memberName:test1*/
|
|
/*b|c.member: memberName:test*/
|
|
some more code
|
|
''',
|
|
actualData: {
|
|
'b': {new MemberId('memberName'): 'test1'},
|
|
},
|
|
expectedResult: '''
|
|
some code
|
|
/*a|b.member: memberName:test1*/
|
|
/*c.member: memberName:test*/
|
|
some more code
|
|
''',
|
|
);
|
|
|
|
testString(
|
|
'''
|
|
some code
|
|
/*a|b.member: memberName:test1*/
|
|
/*c.member: memberName:test*/
|
|
some more code
|
|
''',
|
|
actualData: {
|
|
'c': {new MemberId('memberName'): 'test1'},
|
|
},
|
|
expectedResult: '''
|
|
some code
|
|
/*member: memberName:test1*/
|
|
some more code
|
|
''',
|
|
);
|
|
|
|
testString(
|
|
'/*test*/',
|
|
actualData: {
|
|
'a': {new NodeId(0, IdKind.node): 'test1'},
|
|
},
|
|
expectedResult: '/*a.test1*//*b|c.test*/',
|
|
);
|
|
|
|
testString(
|
|
'/*a.test1*//*b|c.test*/',
|
|
actualData: {
|
|
'b': {new NodeId(0, IdKind.node): 'test1'},
|
|
},
|
|
expectedResult: '/*a|b.test1*//*c.test*/',
|
|
);
|
|
|
|
testString(
|
|
'/*a|b.test1*//*c.test*/',
|
|
actualData: {
|
|
'c': {new NodeId(0, IdKind.node): 'test1'},
|
|
},
|
|
expectedResult: '/*test1*/',
|
|
);
|
|
|
|
testString('/*test*/', actualData: {'c': {}}, expectedResult: '/*a|b.test*/');
|
|
|
|
testString(
|
|
'/*a|b.test*/',
|
|
actualData: {'b': {}},
|
|
expectedResult: '/*a.test*/',
|
|
);
|
|
|
|
testString('/*a.test*/', actualData: {'a': {}}, expectedResult: '');
|
|
|
|
testString(
|
|
'''
|
|
some code
|
|
memberName() {}
|
|
some more code
|
|
''',
|
|
actualData: {
|
|
'a': {new MemberId('memberName'): 'test'},
|
|
},
|
|
memberOffset: 10,
|
|
expectedResult: '''
|
|
some code
|
|
/*a.member: memberName:test*/
|
|
memberName() {}
|
|
some more code
|
|
''',
|
|
);
|
|
|
|
testString(
|
|
'''
|
|
some code
|
|
void memberName() {}
|
|
some more code
|
|
''',
|
|
actualData: {
|
|
'a': {new MemberId('memberName'): 'test'},
|
|
},
|
|
memberOffset: 15,
|
|
expectedResult: '''
|
|
some code
|
|
/*a.member: memberName:test*/
|
|
void memberName() {}
|
|
some more code
|
|
''',
|
|
);
|
|
|
|
testString(
|
|
'''
|
|
class Class {
|
|
void memberName() {}
|
|
}
|
|
''',
|
|
actualData: {
|
|
'a': {new MemberId('memberName'): 'test'},
|
|
},
|
|
memberOffset: 21,
|
|
expectedResult: '''
|
|
class Class {
|
|
/*a.member: memberName:test*/
|
|
void memberName() {}
|
|
}
|
|
''',
|
|
);
|
|
|
|
testString(
|
|
'''
|
|
class Class {
|
|
void memberName() {}
|
|
}
|
|
''',
|
|
actualData: {
|
|
'a': {
|
|
new ClassId('className'): 'test1',
|
|
new MemberId('memberName'): 'test2',
|
|
},
|
|
},
|
|
classOffset: 6,
|
|
memberOffset: 21,
|
|
expectedResult: '''
|
|
/*a.class: className:test1*/
|
|
class Class {
|
|
/*a.member: memberName:test2*/
|
|
void memberName() {}
|
|
}
|
|
''',
|
|
);
|
|
|
|
testString(
|
|
'''
|
|
// bla
|
|
// bla
|
|
// bla
|
|
|
|
class Class {}
|
|
''',
|
|
actualData: {
|
|
'a': {new LibraryId(mainUri): 'test'},
|
|
},
|
|
memberOffset: 15,
|
|
expectedResult: '''
|
|
// bla
|
|
// bla
|
|
// bla
|
|
|
|
/*a.library: test*/
|
|
|
|
class Class {}
|
|
''',
|
|
);
|
|
|
|
testFeatures('''
|
|
some code
|
|
/*member: memberName:
|
|
test1=a,
|
|
test2=[
|
|
b,
|
|
c],
|
|
test3=d
|
|
*/
|
|
some more code
|
|
''');
|
|
testFeatures(
|
|
'''
|
|
some code
|
|
/*member: memberName:
|
|
test1=a,
|
|
test2=[
|
|
b,
|
|
c],
|
|
test3=d
|
|
*/
|
|
some more code
|
|
''',
|
|
actualData: {
|
|
'a': {new MemberId('memberName'): 'test1=b,test2=[c,d],test3=e'},
|
|
},
|
|
expectedResult: '''
|
|
some code
|
|
/*a.member: memberName:
|
|
test1=b,
|
|
test2=[
|
|
c,
|
|
d],
|
|
test3=e
|
|
*/
|
|
/*b|c.member: memberName:
|
|
test1=a,
|
|
test2=[
|
|
b,
|
|
c],
|
|
test3=d
|
|
*/
|
|
some more code
|
|
''',
|
|
);
|
|
// TODO(johnniwinther): Should new data reuse an existing encoding when that
|
|
// differs from the pretty printed encoding?
|
|
testFeatures(
|
|
'''
|
|
some code
|
|
/*a.member: memberName:test1=b,test2=[c,d],test3=e*/
|
|
/*b|c.member: memberName:
|
|
test1=a,
|
|
test2=[
|
|
b,
|
|
c],
|
|
test3=d
|
|
*/
|
|
some more code
|
|
''',
|
|
actualData: {
|
|
'b': {new MemberId('memberName'): 'test1=b,test2=[c,d],test3=e'},
|
|
},
|
|
expectedResult: '''
|
|
some code
|
|
/*a.member: memberName:test1=b,test2=[c,d],test3=e*/
|
|
/*b.member: memberName:
|
|
test1=b,
|
|
test2=[
|
|
c,
|
|
d],
|
|
test3=e
|
|
*/
|
|
/*c.member: memberName:
|
|
test1=a,
|
|
test2=[
|
|
b,
|
|
c],
|
|
test3=d
|
|
*/
|
|
some more code
|
|
''',
|
|
);
|
|
testFeatures(
|
|
'''
|
|
some code
|
|
/*a.member: memberName:
|
|
test1=b,
|
|
test2=[
|
|
c,
|
|
d],
|
|
test3=e
|
|
*/
|
|
/*b|c.member: memberName:
|
|
test1=a,
|
|
test2=[
|
|
b,
|
|
c],
|
|
test3=d
|
|
*/
|
|
some more code
|
|
''',
|
|
actualData: {
|
|
'b': {new MemberId('memberName'): 'test1=b,test2=[c,d],test3=e'},
|
|
},
|
|
expectedResult: '''
|
|
some code
|
|
/*a|b.member: memberName:
|
|
test1=b,
|
|
test2=[
|
|
c,
|
|
d],
|
|
test3=e
|
|
*/
|
|
/*c.member: memberName:
|
|
test1=a,
|
|
test2=[
|
|
b,
|
|
c],
|
|
test3=d
|
|
*/
|
|
some more code
|
|
''',
|
|
);
|
|
testFeatures(
|
|
'''
|
|
some code
|
|
/*a|b.member: memberName:
|
|
test1=b,
|
|
test2=[
|
|
c,
|
|
d],
|
|
test3=e
|
|
*/
|
|
/*c.member: memberName:
|
|
test1=a,
|
|
test2=[
|
|
b,
|
|
c],
|
|
test3=d
|
|
*/
|
|
some more code
|
|
''',
|
|
actualData: {
|
|
'c': {new MemberId('memberName'): 'test1=b,test2=[c,d],test3=e'},
|
|
},
|
|
expectedResult: '''
|
|
some code
|
|
/*member: memberName:
|
|
test1=b,
|
|
test2=[
|
|
c,
|
|
d],
|
|
test3=e
|
|
*/
|
|
some more code
|
|
''',
|
|
);
|
|
}
|
|
|
|
void testString(
|
|
String text, {
|
|
Map<String, Map<Id, String>> actualData = const {},
|
|
String? expectedResult,
|
|
int classOffset = 0,
|
|
int memberOffset = 0,
|
|
}) {
|
|
testGeneral(
|
|
const StringDataInterpreter(),
|
|
text,
|
|
actualData: actualData,
|
|
expectedResult: expectedResult,
|
|
classOffset: classOffset,
|
|
memberOffset: memberOffset,
|
|
);
|
|
|
|
testFeatures(
|
|
text,
|
|
actualData: actualData,
|
|
expectedResult: expectedResult,
|
|
classOffset: classOffset,
|
|
memberOffset: memberOffset,
|
|
);
|
|
}
|
|
|
|
void testFeatures(
|
|
String text, {
|
|
Map<String, Map<Id, String>> actualData = const {},
|
|
String? expectedResult,
|
|
int classOffset = 0,
|
|
int memberOffset = 0,
|
|
}) {
|
|
Map<String, Map<Id, Features>> actualFeatures = {};
|
|
actualData.forEach((String marker, Map<Id, String> data) {
|
|
Map<Id, Features> features = actualFeatures[marker] = {};
|
|
data.forEach((Id id, String text) {
|
|
features[id] = Features.fromText(text.trim());
|
|
});
|
|
});
|
|
testGeneral(
|
|
const FeaturesDataInterpreter(),
|
|
text,
|
|
actualData: actualFeatures,
|
|
expectedResult: expectedResult,
|
|
classOffset: classOffset,
|
|
memberOffset: memberOffset,
|
|
);
|
|
}
|
|
|
|
void testGeneral<T>(
|
|
DataInterpreter<T> dataInterpreter,
|
|
String text, {
|
|
Map<String, Map<Id, T>> actualData = const {},
|
|
String? expectedResult,
|
|
int classOffset = 0,
|
|
int memberOffset = 0,
|
|
}) {
|
|
expectedResult ??= text;
|
|
AnnotatedCode code = new AnnotatedCode.fromText(
|
|
text,
|
|
commentStart,
|
|
commentEnd,
|
|
);
|
|
Map<String, MemberAnnotations<IdValue>> expectedMaps = {};
|
|
for (String marker in markers) {
|
|
expectedMaps[marker] = new MemberAnnotations<IdValue>();
|
|
}
|
|
computeExpectedMap(
|
|
mainUri,
|
|
mainUri.path,
|
|
code,
|
|
expectedMaps,
|
|
onFailure: (String message) {
|
|
throw message;
|
|
},
|
|
);
|
|
|
|
Map<String, Map<Uri, Map<Id, ActualData<T>>>> actualAnnotations = {};
|
|
actualData.forEach((String marker, Map<Id, T> data) {
|
|
Map<Uri, Map<Id, ActualData<T>>> map = actualAnnotations[marker] = {};
|
|
Map<Id, ActualData<T>> actualData = map[mainUri] = {};
|
|
data.forEach((Id id, T value) {
|
|
int offset;
|
|
if (id is NodeId) {
|
|
offset = id.value;
|
|
} else if (id is MemberId) {
|
|
offset = memberOffset;
|
|
} else if (id is ClassId) {
|
|
offset = classOffset;
|
|
} else {
|
|
offset = 0;
|
|
}
|
|
actualData[id] = new ActualData<T>(id, value, mainUri, offset, text);
|
|
});
|
|
});
|
|
|
|
Map<Uri, List<Annotation>> annotations = computeAnnotationsPerUri<T>(
|
|
{mainUri: code},
|
|
expectedMaps,
|
|
mainUri,
|
|
actualAnnotations,
|
|
dataInterpreter,
|
|
);
|
|
AnnotatedCode generated = new AnnotatedCode(
|
|
code.annotatedCode,
|
|
code.sourceCode,
|
|
annotations[mainUri]!,
|
|
);
|
|
String actualResult = generated.toText();
|
|
if (expectedResult != actualResult) {
|
|
print("Unexpected result for '$text' with actualData=$actualData");
|
|
print('---expected-------------------------------------------------------');
|
|
print(expectedResult);
|
|
print('---actual---------------------------------------------------------');
|
|
print(actualResult);
|
|
throw StateError('Expected $expectedResult, got $actualResult');
|
|
}
|
|
}
|