blob: 4c8fa8d375752acaf9d29cfb4c0b897fb0b795aa [file] [log] [blame]
// 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');
}
}