| // 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'); | |
| } | |
| } |