// Copyright (c) 2017, 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 'dart:collection'; import 'package:test/test.dart'; import 'completion_test_support.dart'; void main() { var builder = CompletionTestBuilder(); builder.buildAll(); } /// A builder that builds the completion tests. class CompletionTestBuilder { /// 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. int expectedFailCount = 0; void buildAll() { buildNumberedTests(); buildCommentSnippetTests(); buildCompletionTests(); buildOtherTests(); buildLibraryTests(); var testCount = expectedPassCount + expectedFailCount; print( 'Total $testCount tests, of which $expectedFailCount are expected to fail.'); } void buildCommentSnippetTests() { buildTests('testCommentSnippets001', ''' class X {static final num MAX = 0;num yc,xc;mth() {xc = yc = MA!1X;x!2c.abs();num f = M!3AX;}}''', ['1+MAX', '2+xc', '3+MAX']); buildTests('testCommentSnippets002', ''' class Y {String x='hi';mth() {x.l!1ength;int n = 0;x!2.codeUnitAt(n!3);}}''', ['1+length', '2+x', '3+n']); buildTests('testCommentSnippets004', ''' class A {!1int x; !2mth() {!3int y = this.!5x!6;}}class B{}''', ['1+A', '2+B', '3+x', '3-y', '5+mth', '6+x']); buildTests('testCommentSnippets005', ''' class Date { static Date JUN, JUL;}class X { m() { return Da!1te.JU!2L; }}''', ['1+Date', '2+JUN', '2+JUL']); buildTests('testCommentSnippets007', ''' class C {mth(Map x, !1) {}mtf(!2, Map x) {}m() {for (in!3t i=0; i<5; i++); A!4 x;}}class int{}class Arrays{}''', ['1+bool', '2+bool', '3+int', '4+Arrays']); buildTests('testCommentSnippets008', ''' class Date{}final num M = Dat!1''', ['1+Date']); // space, char, eol are important buildTests( 'testCommentSnippets009', ''' class Maps{}class x extends!5 !2M!3 !4implements!6 !1\n{}''', [ '1+Map', '2+Maps', '3+Maps', '4-Maps', '4+implements', '5-Maps', '6-Map', '6+implements' ], failingTests: '46'); // space, char, eol are important buildTests('testCommentSnippets010', ''' class x implements !1{}''', ['1+Map']); // space, char, eol are important buildTests('testCommentSnippets011', ''' class x implements M!1{}''', ['1+Map']); // space, char, eol are important buildTests('testCommentSnippets012', ''' class x implements M!1\n{}''', ['1+Map']); buildTests('testCommentSnippets013', ''' class x !2{!1}!3''', ['1+num', '2-num', '3+num']); // trailing space is important buildTests('testCommentSnippets014', ''' typedef n!1 ;''', ['1+num']); buildTests('testCommentSnippets015', ''' class D {f(){} g(){f!1(f!2);}}''', ['1+f', '2+f']); buildTests('testCommentSnippets016', ''' class F {m() { m(); !1}}''', ['1+m']); buildTests('testCommentSnippets017', ''' class F {var x = !1false;}''', ['1+true']); buildTests('testCommentSnippets018', ''' class Map{}class Arrays{}class C{ m(!1){} n(!2 x, q)''', [ '1+Map', '1+dynamic', '1+void', '1-null', '2+Arrays', '2-void', '2-null' ]); buildTests('testCommentSnippets019', ''' class A{m(){Object x;x.!1/**/clear()''', ['1+toString']); buildTests('testCommentSnippets020', ''' classMap{}class tst {var newt;void newf(){}test() {var newz;new!1/**/;}}''', ['1+newt', '1+newf', '1+newz', '1-Map']); buildTests('testCommentSnippets021', ''' class Map{}class tst {var newt;void newf(){}test() {var newz;new !1/**/;}}''', ['1+Map', '1-newt']); buildTests('testCommentSnippets022', ''' class Map{}class F{m(){new !1;}}''', ['1+Map']); buildTests('testCommentSnippets022a', ''' class Map{}class F{m(){new !1''', ['1+Map']); buildTests('testCommentSnippets022b', ''' class Map{factory Map.qq(){return null;}}class F{m(){new Map.!1qq();}}''', ['1+qq']); buildTests('testCommentSnippets023', ''' class X {X c; X(this.!1c!3) : super() {c.!2}}''', ['1+c', '2+c', '3+c']); buildTests('testCommentSnippets024', ''' class q {m(Map q){var x;m(!1)}n(){var x;n(!2)}}''', ['1+x', '2+x']); buildTests('testCommentSnippets025', ''' class C {num m() {var q; num x=!1 q!3 + !2/**/;}}''', ['1+q', '2+q', '3+q']); buildTests('testCommentSnippets026', ''' class List{}class a implements !1{}''', ['1+List']); buildTests('testCommentSnippets027', ''' class String{}class List{}class test {}''', ['1+List', '2+String', '2-List']); buildTests('testCommentSnippets028', ''' class String{}class List{}class DateTime{}typedef T Y(List input);''', ['1+DateTime', '1+String']); buildTests('testCommentSnippets029', ''' interface A default B {}''', ['1+DateTime', '2+List']); buildTests('testCommentSnippets030', ''' class Bar {const Bar(!1T!2 k);T!3 m(T!4 a, T!5 b){}final T!6 f = null;}''', ['1+T', '2+T', '3+T', '4+T', '5+T', '6+T']); buildTests('testCommentSnippets031', ''' class Bar {m(x){if (x is !1) return;if (x is!!!2)}}''', ['1+Bar', '1+T', '2+T', '2+Bar']); buildTests( 'testCommentSnippets032', ''' class Fit{}class Bar {const !2F!1ara();}''', ['1+Fit', '1+Fara', '1-Bar', '2+Fit'], failingTests: '1'); // Type propagation buildTests('testCommentSnippets033', ''' class List{add(){}length(){}}t1() {var x;if (x is List) {x.!1add(3);}}''', ['1+add', '1+length']); // Type propagation buildTests('testCommentSnippets035', ''' class List{clear(){}length(){}}t3() {var x=[], y=x.!1length();x.!2clear();}''', ['1+length', '2+clear']); buildTests('testCommentSnippets036', ''' class List{}t3() {var x=new List!1}''', ['1+List']); buildTests('testCommentSnippets037', ''' class List{factory List.from(){}}t3() {var x=new List.!1}''', ['1+from']); buildTests('testCommentSnippets038', ''' f(){int xa; String s = '\$x!1';}''', ['1+xa']); buildTests('testCommentSnippets038a', ''' int xa; String s = '\$x!1\'''', ['1+xa']); buildTests('testCommentSnippets039', ''' f(){int xa; String s = '\$!1';}''', ['1+xa']); buildTests('testCommentSnippets039a', ''' int xa; String s = '\$!1\'''', ['1+xa']); buildTests('testCommentSnippets040', ''' class List{add(){}}class Map{}class X{m(){List list; list.!1 Map map;}}''', ['1+add']); buildTests('testCommentSnippets041', ''' class List{add(){}length(){}}class X{m(){List list; list.!1 zox();}}''', ['1+add']); buildTests('testCommentSnippets042', ''' class DateTime{static const int WED=3;int get day;}fd(){DateTime d=new DateTime.now();d.!1WED!2;}''', ['1+day', '2-WED']); buildTests('testCommentSnippets043', ''' class L{var k;void.!1}''', ['1-k']); buildTests('testCommentSnippets044', ''' class List{}class XXX {XXX.fisk();}main() {main(); new !1}}''', ['1+List', '1+XXX.fisk']); buildTests('testCommentSnippets045', ''' class List{}class XXX {XXX.fisk();}main() {main(); !1}}''', ['1+List', '1+XXX.fisk']); buildTests('testCommentSnippets047', ''' f(){int x;int y=!1;}''', ['1+x']); buildTests('testCommentSnippets048', ''' import 'dart:convert' as json;f() {var x=new js!1}''', ['1+json']); buildTests('testCommentSnippets049', ''' import 'dart:convert' as json; import 'dart:convert' as jxx; class JsonDecoderX{} f1() {var x=new !2j!1s!3}''', [ '1+json', '1+jxx', '2+json', '2+jxx', '2-JsonDecoder', '3+json', '3-jxx' ]); buildTests('testCommentSnippets050', ''' class xdr { xdr(); const xdr.a(a,b,c); xdr.b(); f() => 3; } class xa{} k() { new x!1dr().f(); const x!2dr.!3a(1, 2, 3); }''', [ '1+xdr', '1+xa', '1+xdr.a', '1+xdr.b', '2+xa', // suggest default constructor '2+xdr', // suggest normal constructor '2+xdr.a', '2+xdr.b', // suggest named constructor '3+b', // suggest named constructor '3+a' ]); // Type propagation. buildTests('testCommentSnippets051', ''' class String{int length(){} String toUpperCase(){} bool isEmpty(){}}class Map{getKeys(){}} void r() { var v; if (v is String) { v.!1length; v.!2getKeys; } }''', ['1+length', '2-getKeys']); // Type propagation. buildTests('testCommentSnippets052', ''' class String{int length(){} String toUpperCase(){} bool isEmpty(){}}class Map{getKeys(){}} void r() { List values = ['a','b','c']; for (var v in values) { v.!1toUpperCase; v.!2getKeys; } }''', ['1+toUpperCase', '2-getKeys']); buildTests('testCommentSnippets055', ''' class String{int length(){} String toUpperCase(){} bool isEmpty(){}}class Map{getKeys(){}} void r() { String v; if (v is Object) { v.!1toUpperCase; } }''', ['1+toUpperCase']); buildTests( 'testCommentSnippets058', ''' typedef vo!2id callback(int k); void x(callback q){} void r() { callback v; x(!1); }''', ['1+v', '2+void'], failingTests: '2'); buildTests('testCommentSnippets060', ''' class Map{} abstract class MM extends Map{factory MM() => new Map();} class Z { MM x; f() { x!1 } }''', ['1+x', '1-x[]']); buildTests('testCommentSnippets061', ''' class A{m(){!1f(3);!2}}n(){!3f(3);!4}f(x)=>x*3;''', ['1+f', '1+n', '2+f', '2+n', '3+f', '3+n', '4+f', '4+n']); buildTests('testCommentSnippets064', ''' class Spline { Line c; Spline a() { return this; } Line b() { return null; } Spline f() { Line x = new Line(); x.!9h()..!1a()..!2b().!7g(); x.!8j..!3b()..!4c..!6c..!5a(); } } class Line { Spline j; Line g() { return this; } Spline h() { return null; } }''', [ '1+a', '2+b', '1-g', '2-h', '3+b', '4+c', '5+a', '6+c', '7+g', '8+j', '9+h' ]); buildTests('testCommentSnippets065', ''' class Spline { Line c; Spline a() { return this; } Line b() { return null; } Spline f() { Line x = new Line(); x.h()..!1; } } class Line { Spline j; Line g() { return this; } Spline h() { return null; } }''', ['1+a']); buildTests('testCommentSnippets066', ''' class Spline { Line c; Spline a() { return this; } Line b() { return null; } Spline f() { Line x = new Line(); x.h()..a()..!1; } } class Line { Spline j; Line g() { return this; } Spline h() { return null; } }''', ['1+b']); buildTests('testCommentSnippets067', ''' class Spline { Line c; Spline a() { return this; } Line b() { return null; } Spline f() { Line x = new Line(); x.h()..a()..c..!1; } } class Line { Spline j; Line g() { return this; } Spline h() { return null; } }''', ['1+b']); buildTests('testCommentSnippets068', ''' class Spline { Line c; Spline a() { return this; } Line b() { return null; } Spline f() { Line x = new Line(); x.j..b()..c..!1; } } class Line { Spline j; Line g() { return this; } Spline h() { return null; } }''', ['1+c']); buildTests('testCommentSnippets069', ''' class Spline { Line c; Spline a() { return this; } Line b() { return null; } Spline f() { Line x = new Line(); x.j..b()..!1; } } class Line { Spline j; Line g() { return this; } Spline h() { return null; } }''', ['1+c']); buildTests('testCommentSnippets070', ''' class Spline { Line c; Spline a() { return this; } Line b() { return null; } Spline f() { Line x = new Line(); x.j..!1; } } class Line { Spline j; Line g() { return this; } Spline h() { return null; } }''', ['1+b']); buildTests('testCommentSnippets072', ''' class X { int _p; set p(int x) => _p = x; } f() { X x = new X(); x.!1p = 3; }''', ['1+p']); buildTests('testCommentSnippets073', ''' class X { m() { JSON.stri!1; X f = null; } } class JSON { static stringify() {} }''', ['1+stringify']); buildTests('testCommentSnippets074', ''' class X { m() { _x!1 } _x1(){} }''', ['1+_x1']); buildTests('testCommentSnippets075', ''' p(x)=>0;var E;f(q)=>!1p(!2E);''', ['1+p', '2+E']); buildTests('testCommentSnippets076', ''' class Map{}class List{}class int{}main() {var m=new Map>,List>();}''', ['1+List', '2+int', '3+int']); buildTests('testCommentSnippets076a', ''' class Map{}class List{}class int{}main() {var m=new Map>,List>();}''', ['1+List', '2+int', '3+int']); buildTests('testCommentSnippets077', ''' class FileMode { static const READ = const FileMode._internal(0); static const WRITE = const FileMode._internal(1); static const APPEND = const FileMode._internal(2); const FileMode._internal(int this._mode); factory FileMode._internal1(int this._mode); factory FileMode(_mode); final int _mode; } class File { File(String path); File.fromPath(Path path); } f() => new Fil!1''', [ '1+File', '1+File.fromPath', '1+FileMode', '1+FileMode._internal1', '1+FileMode._internal' ]); buildTests('testCommentSnippets078', ''' class Map{static from()=>null;clear(){}}void main() { Map.!1 }''', ['1+from', '1-clear']); // static method, instance method buildTests('testCommentSnippets079', ''' class Map{static from()=>null;clear(){}}void main() { Map s; s.!1 }''', ['1-from', '1+clear']); // static method, instance method buildTests('testCommentSnippets080', ''' class RuntimeError{var message;}void main() { RuntimeError.!1 }''', ['1-message']); // field buildTests( 'testCommentSnippets081', ''' class Foo {this.!1}''', ['1-Object'], failingTests: '1'); // https://github.com/dart-lang/sdk/issues/33992 buildTests( 'testCommentSnippets082', ''' class HttpRequest {} class HttpResponse {} main() { var v = (HttpRequest req, HttpResp!1) }''', ['1+HttpResponse'], failingTests: '1'); buildTests('testCommentSnippets083', ''' main() {(.!1)}''', ['1-toString']); buildTests('testCommentSnippets083a', ''' main() { .!1 }''', ['1-toString']); buildTests('testCommentSnippets083b', ''' main() { null.!1 }''', ['1+toString']); buildTests('testCommentSnippets085', ''' class List{}class Map{}class Z extends List with !1Ma!2p {}''', ['1+List', '1+Map', '2+Map', '2-List']); buildTests( 'testCommentSnippets086', ''' class Q{f(){xy() {!2};x!1y();}}''', ['1+xy', '2+f', '2-xy'], failingTests: '2'); buildTests('testCommentSnippets087', ''' class Map{}class Q extends Object with !1Map {}''', ['1+Map', '1-HashMap']); buildTests('testCommentSnippets088', ''' class A { int f; B m(){} } class B extends A { num f; A m(){} } class Z { B q; f() {q.!1} }''', ['1+f', '1+m']); // f->num, m()->A buildTests( 'testCommentSnippets089', ''' class Q { fqe() { xya() { xyb() { !1 } !3 xyb(); }; xza() { !2 } xya(); !4 xza(); } fqi() { !5 } }''', [ '1+fqe', '1+fqi', '1+Q', '1-xya', '1-xyb', '1-xza', '2+fqe', '2+fqi', '2+Q', '2-xya', '2-xyb', '2-xza', '3+fqe', '3+fqi', '3+Q', '3-xya', '3+xyb', '3-xza', '4+fqe', '4+fqi', '4+Q', '4+xya', '4-xyb', '4+xza', '5+fqe', '5+fqi', '5+Q', '5-xya', '5-xyb', '5-xza' ], failingTests: '123'); buildTests('testCommentSnippets090', ''' class X { f() { var a = 'x'; a.!1 }}''', ['1+length']); } void buildCompletionTests() { buildTests('testCompletion_alias_field', ''' typedef int fnint(int k); fn!1int x;''', ['1+fnint']); buildTests( 'testCompletion_annotation_argumentList', ''' class AAA {", const AAA({int aaa, int bbb});", }", ", @AAA(!1) main() { }''', [ '1+AAA' /*":" + ProposalKind.ARGUMENT_LIST*/, '1+aaa', '1+bbb' ], failingTests: '1'); buildTests( 'testCompletion_annotation_topLevelVar', ''' const fooConst = null; final fooNotConst = null; const bar = null; @foo!1 main() { }''', ['1+fooConst', '1-fooNotConst', '1-bar'], failingTests: '1'); buildTests('testCompletion_annotation_type', ''' class AAA { const AAA({int a, int b}); const AAA.nnn(int c, int d); } @AAA!1 main() { }''', [ '1+AAA' /*":" + ProposalKind.CONSTRUCTOR*/, '1+AAA.nnn' /*":" + ProposalKind.CONSTRUCTOR*/ ]); buildTests('testCompletion_annotation_type_inClass_withoutMember', ''' class AAA { const AAA(); } class C { @A!1 }''', [ '1+AAA' /*":" + ProposalKind.CONSTRUCTOR*/ ]); buildTests('testCompletion_argument_typeName', ''' class Enum { static Enum FOO = new Enum(); } f(Enum e) {} main() { f(En!1); }''', ['1+Enum']); buildTests('testCompletion_arguments_ignoreEmpty', ''' class A { test() {} } main(A a) { a.test(!1); }''', ['1-test']); buildTests('testCompletion_as_asIdentifierPrefix', ''' main(p) { var asVisible; var v = as!1; }''', ['1+asVisible']); buildTests('testCompletion_as_asPrefixedIdentifierStart', ''' class A { var asVisible; } main(A p) { var v = p.as!1; }''', ['1+asVisible']); buildTests('testCompletion_as_incompleteStatement', ''' class MyClass {} main(p) { var justSomeVar; var v = p as !1 }''', ['1+MyClass', '1-justSomeVar']); buildTests('testCompletion_cascade', ''' class A { aaa() {} } main(A a) { a..!1 aaa(); }''', ['1+aaa', '1-main']); buildTests('testCompletion_combinator_afterComma', ''' import 'dart:math' show cos, !1;''', ['1+pi', '1+sin', '1+Random', '1-String']); buildTests('testCompletion_combinator_ended', ''' import 'dart:math' show !1;"''', ['1+pi', '1+sin', '1+Random', '1-String']); buildTests('testCompletion_combinator_export', ''' export 'dart:math' show !1;"''', ['1+pi', '1+sin', '1+Random', '1-String']); buildTests('testCompletion_combinator_hide', ''' import 'dart:math' hide !1;"''', ['1+pi', '1+sin', '1+Random', '1-String']); buildTests('testCompletion_combinator_notEnded', ''' import 'dart:math' show !1"''', ['1+pi', '1+sin', '1+Random', '1-String']); buildTests('testCompletion_combinator_usePrefix', ''' import 'dart:math' show s!1"''', ['1+sin', '1+sqrt', '1-cos', '1-String']); buildTests( 'testCompletion_constructor_field', ''' class X { X(this.field); int f!1ield;}''', ['1+field'], failingTests: '1'); buildTests( 'testCompletion_constructorArguments_showOnlyCurrent', ''' class A { A.first(int p); A.second(double p); } main() { new A.first(!1); }''', ['1+A.first', '1-A.second'], failingTests: '1'); buildTests( 'testCompletion_constructorArguments_whenPrefixedType', ''' import 'dart:math' as m; main() { new m.Random(!1); }''', ['1+Random:ARGUMENT_LIST'], failingTests: '1'); buildTests('testCompletion_dartDoc_reference_forClass', ''' /** * [int!1] * [method!2] */ class AAA { methodA() {} }''', ['1+int', '1-method', '2+methodA', '2-int']); buildTests('testCompletion_dartDoc_reference_forConstructor', ''' class A { /** * [aa!1] * [int!2] * [method!3] */ A.named(aaa, bbb) {} methodA() {} }''', ['1+aaa', '1-bbb', '2+int', '2-double', '3+methodA']); buildTests( 'testCompletion_dartDoc_reference_forFunction', ''' /** * [aa!1] * [int!2] * [function!3] */ functionA(aaa, bbb) {} functionB() {}''', [ '1+aaa', '1-bbb', '2+int', '2-double', '3+functionA', '3+functionB', '3-int' ], failingTests: '1'); buildTests( 'testCompletion_dartDoc_reference_forFunctionTypeAlias', ''' /** * [aa!1] * [int!2] * [Function!3] */ typedef FunctionA(aaa, bbb) {} typedef FunctionB() {}''', [ '1+aaa', '1-bbb', '2+int', '2-double', '3+FunctionA', '3+FunctionB', '3-int' ], failingTests: '1'); buildTests('testCompletion_dartDoc_reference_forMethod', ''' class A { /** * [aa!1] * [int!2] * [method!3] */ methodA(aaa, bbb) {} methodB() {} }''', [ '1+aaa', '1-bbb', '2+int', '2-double', '3+methodA', '3+methodB', '3-int' ]); buildTests('testCompletion_dartDoc_reference_incomplete', ''' /** * [doubl!1 some text * other text */ class A {} /** * [!2 some text * other text */ class B {} /** * [!3] some text */ class C {}''', [ '1+double', '1-int', '2+int', '2+String', '3+int', '3+String' ]); buildTests('testCompletion_double_inFractionPart', ''' main() { 1.0!1 }''', ['1-abs', '1-main']); buildTests('testCompletion_enum', ''' enum MyEnum {A, B, C} main() { MyEnum.!1; }''', ['1+values', '1+A', '1+B', '1+C']); buildTests('testCompletion_exactPrefix_hasHigherRelevance', ''' var STR; main(p) { var str; str!1; STR!2; Str!3; }''', [ '1+str' /*",rel=" + (CompletionProposal.RELEVANCE_DEFAULT + 1)*/, '1+STR' /*",rel=" + (CompletionProposal.RELEVANCE_DEFAULT + 0)*/, '2+STR' /*",rel=" + (CompletionProposal.RELEVANCE_DEFAULT + 1)*/, '2+str' /*",rel=" + (CompletionProposal.RELEVANCE_DEFAULT + 0)*/, '3+String' /*",rel=" + (CompletionProposal.RELEVANCE_DEFAULT + 1)*/, '3+STR' /*",rel=" + (CompletionProposal.RELEVANCE_DEFAULT + 0)*/, '3+str' /*",rel=" + (CompletionProposal.RELEVANCE_DEFAULT + 0)*/ ]); buildTests('testCompletion_export_dart', ''' import 'dart:math import 'dart:_collection.dev export 'dart:!1''', [ '1+dart:core', '1+dart:math', '1-dart:_collection.dev', ]); buildTests( 'testCompletion_export_noStringLiteral_noSemicolon', ''' import !1 class A {}''', ["1+'dart:!';", "1+'package:!';"], failingTests: '1'); buildTests('testCompletion_forStmt_vars', ''' class int{}class Foo { mth() { for (in!1t i = 0; i!2 < 5; i!3++); }}''', ['1+int', '2+i', '3+i']); buildTests('testCompletion_function', ''' class Foo { int boo = 7; mth() { PNGS.sort((String a, Str!1) => a.compareTo(b)); }}''', ['1+String']); // https://github.com/dart-lang/sdk/issues/33992 buildTests( 'testCompletion_function_partial', ''' class Foo { int boo = 7; mth() { PNGS.sort((String a, Str!1)); }}''', ['1+String'], failingTests: '1'); buildTests( 'testCompletion_functionTypeParameter_namedArgument', ''' typedef FFF(a, b, {x1, x2, y}); main(FFF fff) { fff(1, 2, !1)!2; }''', ['1+x1', '2-x2'], failingTests: '1'); buildTests('testCompletion_ifStmt_field1', ''' class Foo { int myField = 7; mth() { if (!1) {}}}''', ['1+myField']); buildTests('testCompletion_ifStmt_field1a', ''' class Foo { int myField = 7; mth() { if (!1) }}''', ['1+myField']); buildTests('testCompletion_ifStmt_field2', ''' class Foo { int myField = 7; mth() { if (m!1) {}}}''', ['1+myField']); buildTests('testCompletion_ifStmt_field2a', ''' class Foo { int myField = 7; mth() { if (m!1) }}''', ['1+myField']); buildTests('testCompletion_ifStmt_field2b', ''' class Foo { myField = 7; mth() { if (m!1) {}}}''', ['1+myField']); buildTests('testCompletion_ifStmt_localVar', ''' class Foo { mth() { int value = 7; if (v!1) {}}}''', ['1+value']); buildTests('testCompletion_ifStmt_localVara', ''' class Foo { mth() { value = 7; if (v!1) {}}}''', ['1-value']); buildTests('testCompletion_ifStmt_topLevelVar', ''' int topValue = 7; class Foo { mth() { if (t!1) {}}}''', ['1+topValue']); buildTests('testCompletion_ifStmt_topLevelVara', ''' topValue = 7; class Foo { mth() { if (t!1) {}}}''', ['1+topValue']); buildTests( 'testCompletion_ifStmt_unionType_nonStrict', ''' class A { a() => null; x() => null} class B { a() => null; y() => null} void main() { var x; var c; if(c) { x = new A(); } else { x = new B(); } x.!1; }''', ['1+a', '1+x', '1+y'], failingTests: '1'); buildTests( 'testCompletion_ifStmt_unionType_strict', ''' class A { a() => null; x() => null} class B { a() => null; y() => null} void main() { var x; var c; if(c) { x = new A(); } else { x = new B(); } x.!1; }''', ['1+a', '1-x', '1-y'], failingTests: '1'); buildTests('testCompletion_import', ''' import '!1';''', ['1+dart:!', '1+package:!']); buildTests('testCompletion_import_dart', ''' import 'dart:math import 'dart:_collection.dev import 'dart:!1''', [ '1+dart:core', '1+dart:math', '1-dart:_collection.dev', ]); buildTests('testCompletion_import_hasStringLiteral_noSemicolon', ''' import '!1' class A {}''', ['1+dart:!', '1+package:!']); buildTests( 'testCompletion_import_noSpace', ''' import!1''', ["1+ 'dart:!';", "1+ 'package:!';"], failingTests: '1'); buildTests( 'testCompletion_import_noStringLiteral', ''' import !1;''', ["1+'dart:!'", "1+'package:!'"], failingTests: '1'); buildTests( 'testCompletion_import_noStringLiteral_noSemicolon', ''' import !1 class A {}''', ["1+'dart:!';", "1+'package:!';"], failingTests: '1'); buildTests('testCompletion_incompleteClassMember', ''' class A { Str!1 final f = null; }''', ['1+String', '1-bool']); buildTests('testCompletion_incompleteClosure_parameterType', ''' f1(cb(String s)) {} f2(String s) {} main() { f1((Str!1)); f2((Str!2)); }''', ['1+String', '1-bool', '2+String', '2-bool']); buildTests( 'testCompletion_inPeriodPeriod', ''' main(String str) { 1 < str.!1.length; 1 + str.!2.length; 1 + 2 * str.!3.length; }''', ['1+codeUnits', '2+codeUnits', '3+codeUnits'], failingTests: '123'); // no checks, but no exceptions buildTests('testCompletion_instanceCreation_unresolved', ''' class A { } main() { new NoSuchClass(!1); new A.noSuchConstructor(!2); }''', ['1+int', '2+int']); buildTests( 'testCompletion_import_lib', ''' import '!1''', ['1+my_lib.dart'], extraFiles: {'/my_lib.dart': ''}, failingTests: '1'); buildTests('testCompletion_is', ''' class MyClass {} main(p) { var isVariable; if (p is MyCla!1) {} var v1 = p is MyCla!2; var v2 = p is !3; var v2 = p is!4; }''', [ '1+MyClass', '2+MyClass', '3+MyClass', '3-v1', '4+is', '4-isVariable' ]); // https://github.com/dart-lang/sdk/issues/33992 buildTests( 'testCompletion_is_asIdentifierStart', ''' main(p) { var isVisible; var v1 = is!1; var v2 = is!2 }''', ['1+isVisible', '2+isVisible'], failingTests: '12'); buildTests('testCompletion_is_asPrefixedIdentifierStart', ''' class A { var isVisible; } main(A p) { var v1 = p.is!1; var v2 = p.is!2 }''', ['1+isVisible', '2+isVisible']); buildTests('testCompletion_is_incompleteStatement1', ''' class MyClass {} main(p) { var justSomeVar; var v = p is !1 }''', ['1+MyClass', '1-justSomeVar']); buildTests('testCompletion_is_incompleteStatement2', ''' class MyClass {} main(p) { var isVariable; var v = p is!1 }''', ['1+is', '1-isVariable']); buildTests('testCompletion_keyword_in', ''' class Foo { int input = 7; mth() { if (in!1) {}}}''', ['1+input']); buildTests('testCompletion_keyword_syntheticIdentifier', ''' main() { var caseVar; var otherVar; var v = case!1 }''', ['1+caseVar', '1-otherVar']); buildTests('testCompletion_libraryIdentifier_atEOF', ''' library int.!1''', ['1-parse', '1-bool']); buildTests('testCompletion_libraryIdentifier_notEOF', ''' library int.!1''', ['1-parse', '1-bool']); buildTests( 'testCompletion_methodRef_asArg_incompatibleFunctionType', ''' foo( f(int p) ) {} class Functions { static myFuncInt(int p) {} static myFuncDouble(double p) {} } bar(p) {} main(p) { foo( Functions.!1; ); }''', [ '1+myFuncInt' /*":" + ProposalKind.METHOD_NAME*/, '1-myFuncDouble' /*":" + ProposalKind.METHOD_NAME*/ ], failingTests: '1'); buildTests( 'testCompletion_methodRef_asArg_notFunctionType', ''' foo( f(int p) ) {} class Functions { static myFunc(int p) {} } bar(p) {} main(p) { foo( (int p) => Functions.!1; ); }''', [ '1+myFunc' /*":" + ProposalKind.METHOD*/, '1-myFunc' /*":" + ProposalKind.METHOD_NAME*/ ], failingTests: '1'); buildTests('testCompletion_methodRef_asArg_ofFunctionType', ''' foo( f(int p) ) {} class Functions { static int myFunc(int p) {} } main(p) { foo(Functions.!1); }''', [ '1+myFunc' /*":" + ProposalKind.METHOD*/, '1+myFunc' /*":" + ProposalKind.METHOD_NAME*/ ]); buildTests('testCompletion_namedArgument_alreadyUsed', ''' func({foo}) {} main() { func(foo: 0, fo!1); }''', ['1-foo']); buildTests( 'testCompletion_namedArgument_constructor', ''' class A {A({foo, bar}) {}} main() { new A(fo!1); }''', ['1+foo', '1-bar'], failingTests: '1'); buildTests( 'testCompletion_namedArgument_empty', ''' func({foo, bar}) {} main() { func(!1); }''', [ '1+foo' /*":" + ProposalKind.NAMED_ARGUMENT*/, '1-foo' /*":" + ProposalKind.OPTIONAL_ARGUMENT*/ ], failingTests: '1'); buildTests( 'testCompletion_namedArgument_function', ''' func({foo, bar}) {} main() { func(fo!1); }''', ['1+foo', '1-bar'], failingTests: '1'); buildTests('testCompletion_namedArgument_notNamed', ''' func([foo]) {} main() { func(fo!1); }''', ['1-foo']); buildTests('testCompletion_namedArgument_unresolvedFunction', ''' main() { func(fo!1); }''', ['1-foo']); buildTests('testCompletion_newMemberType1', ''' class Collection{}class List extends Collection{}class Foo { !1 }''', ['1+Collection', '1+List']); buildTests('testCompletion_newMemberType2', ''' class Collection{}class List extends Collection{}class Foo {!1}''', ['1+Collection', '1+List']); buildTests('testCompletion_newMemberType3', ''' class Collection{}class List extends Collection{}class Foo {L!1}''', ['1-Collection', '1+List']); buildTests('testCompletion_newMemberType4', ''' class Collection{}class List extends Collection{}class Foo {C!1}''', ['1+Collection', '1-List']); buildTests( 'testCompletion_positionalArgument_constructor', ''' class A { A([foo, bar]); } main() { new A(!1); new A(0, !2); }''', [ '1+foo' /*":" + ProposalKind.OPTIONAL_ARGUMENT*/, '1-bar', '2-foo', '2+bar' /*":" + ProposalKind.OPTIONAL_ARGUMENT*/ ], failingTests: '12'); buildTests( 'testCompletion_positionalArgument_function', ''' func([foo, bar]) {} main() { func(!1); func(0, !2); }''', [ '1+foo' /*":" + ProposalKind.OPTIONAL_ARGUMENT*/, '1-bar', '2-foo', '2+bar' /*":" + ProposalKind.OPTIONAL_ARGUMENT*/ ], failingTests: '12'); buildTests( 'testCompletion_preferStaticType', ''' class A { foo() {} } class B extends A { bar() {} } main() { A v = new B(); v.!1 }''', [ '1+foo', '1-bar,potential=false,declaringType=B', '1+bar,potential=true,declaringType=B' ], failingTests: '1'); buildTests('testCompletion_privateElement_sameLibrary_constructor', ''' class A { A._c(); A.c(); } main() { new A.!1 }''', ['1+_c', '1+c']); buildTests('testCompletion_privateElement_sameLibrary_member', ''' class A { _m() {} m() {} } main(A a) { a.!1 }''', ['1+_m', '1+m']); buildTests('testCompletion_propertyAccess_whenClassTarget', ''' class A { static int FIELD; int field; } main() { A.!1 }''', ['1+FIELD', '1-field']); buildTests('testCompletion_propertyAccess_whenClassTarget_excludeSuper', ''' class A { static int FIELD_A; static int methodA() {} } class B extends A { static int FIELD_B; static int methodB() {} } main() { B.!1; }''', ['1+FIELD_B', '1-FIELD_A', '1+methodB', '1-methodA']); buildTests('testCompletion_propertyAccess_whenInstanceTarget', ''' class A { static int FIELD; int fieldA; } class B { A a; } class C extends A { int fieldC; } main(B b, C c) { b.a.!1; c.!2; }''', ['1-FIELD', '1+fieldA', '2+fieldC', '2+fieldA']); buildTests('testCompletion_return_withIdentifierPrefix', ''' f() { var vvv = 42; return v!1 }''', ['1+vvv']); buildTests('testCompletion_return_withoutExpression', ''' f() { var vvv = 42; return !1 }''', ['1+vvv']); buildTests('testCompletion_staticField1', ''' class num{}class Sunflower {static final n!2um MAX_D = 300;nu!3m xc, yc;Sun!4flower() {x!Xc = y!Yc = MA!1 }}''', ['1+MAX_D', 'X+xc', 'Y+yc', '2+num', '3+num', '4+Sunflower']); buildTests('testCompletion_staticField_withoutVarOrFinal', ''' class num{}class Sunflower {static n!1}''', ['1+num']); buildTests('testCompletion_super_superType', ''' class A { var fa; ma() {} } class B extends A { var fb; mb() {} main() { super.!1 } }''', ['1+fa', '1-fb', '1+ma', '1-mb']); buildTests( 'testCompletion_superConstructorInvocation_noNamePrefix', ''' class A { A.fooA(); A.fooB(); A.bar(); } class B extends A { B() : super.!1 }''', ['1+fooA', '1+fooB', '1+bar'], failingTests: '1'); buildTests( 'testCompletion_superConstructorInvocation_withNamePrefix', ''' class A { A.fooA(); A.fooB(); A.bar(); } class B extends A { B() : super.f!1 }''', ['1+fooA', '1+fooB', '1-bar'], failingTests: '1'); buildTests( 'testCompletion_this_bad_inConstructorInitializer', ''' class A { var f; A() : f = this.!1; }''', ['1-toString'], failingTests: '1'); buildTests( 'testCompletion_this_bad_inFieldDeclaration', ''' class A { var f = this.!1; }''', ['1-toString'], failingTests: '1'); buildTests( 'testCompletion_this_bad_inStaticMethod', ''' class A { static m() { this.!1; } }''', ['1-toString'], failingTests: '1'); buildTests( 'testCompletion_this_bad_inTopLevelFunction', ''' main() { this.!1; }''', ['1-toString'], failingTests: '1'); buildTests( 'testCompletion_this_bad_inTopLevelVariableDeclaration', ''' var v = this.!1;''', ['1-toString'], failingTests: '1'); buildTests('testCompletion_this_OK_inConstructorBody', ''' class A { var f; m() {} A() { this.!1; } }''', ['1+f', '1+m']); buildTests('testCompletion_this_OK_localAndSuper', ''' class A { var fa; ma() {} } class B extends A { var fb; mb() {} main() { this.!1 } }''', ['1+fa', '1+fb', '1+ma', '1+mb']); buildTests('testCompletion_topLevelField_init2', ''' class DateTime{static var JUN;}final num M = Dat!1eTime.JUN;''', ['1+DateTime', '1-void']); buildTests('testCompletion_while', ''' class Foo { int boo = 7; mth() { while (b!1) {} }}''', ['1+boo']); } void buildLibraryTests() { Map sources = HashMap(); buildTests('test_export_ignoreIfThisLibraryExports', ''' export 'dart:math'; libFunction() {}; main() { !1 }''', ['1-cos', '1+libFunction']); sources.clear(); sources['/lib.dart'] = ''' library lib; export 'dart:math' hide sin; libFunction() {};'''; buildTests( 'test_export_showIfImportLibraryWithExport', ''' import 'lib.dart' as p; main() { p.!1 }''', ['1+cos', '1-sin', '1+libFunction'], extraFiles: sources, failingTests: '1'); buildTests('test_importPrefix_hideCombinator', ''' import 'dart:math' as math hide pi; main() { math.!1 }''', ['1-pi', '1+ln10']); buildTests('test_importPrefix_showCombinator', ''' import 'dart:math' as math show pi; main() { math.!1 }''', ['1+pi', '1-ln10']); sources.clear(); sources['/lib.dart'] = ''' library lib class _A foo() {} class A extends _A { }'''; buildTests( 'test_memberOfPrivateClass_otherLibrary', ''' import 'lib.dart'; main(A a) { a.!1 }''', ['1+foo'], extraFiles: sources, failingTests: '1'); sources.clear(); sources['/lib.dart'] = ''' library lib; class A { A.c(); A._c(); }'''; buildTests( 'test_noPrivateElement_otherLibrary_constructor', ''' import 'lib.dart'; main() { new A.!1 }''', ['1-_c', '1+c'], failingTests: '1'); sources.clear(); sources['/lib.dart'] = ''' library lib; class A { var f; var _f; }'''; buildTests( 'test_noPrivateElement_otherLibrary_member', ''' import 'lib.dart'; main(A a) { a.!1 }''', ['1-_f', '1+f'], extraFiles: sources, failingTests: '1'); sources.clear(); sources['/firth.dart'] = ''' library firth; class SerializationException { const SerializationException(); }'''; buildTests( 'testLibrary001', ''' import 'firth.dart'; main() { throw new Seria!1lizationException();}''', ['1+SerializationException'], extraFiles: sources, failingTests: '1'); // Type propagation. // TODO Include corelib analysis (this works in the editor) buildTests( 'testLibrary002', '''t2() {var q=[0],z=q.!1length;q.!2clear();}''', ['1+length', '1+isEmpty', '2+clear']); // TODO Include corelib analysis buildTests('testLibrary003', '''class X{var q; f() {q.!1a!2}}''', ['1+end', '2+abs', '2-end'], failingTests: '12'); // TODO Include corelib analysis // Resolving dart:html takes between 2.5s and 30s; json, about 0.12s buildTests('testLibrary004', ''' library foo; import 'dart:convert' as json; class JsonDecoderX{} f1() {var x=new json.!1} f2() {var x=new json.JsonDe!2} f3() {var x=new json.JsonDecoder!3}''', [ '1+JsonDecoder', '1-JsonDecoderX', '2+JsonDecoder', '2-JsonDecoderX', '3+JsonDecoder', '3-JsonDecoderX' ]); // TODO Enable after type propagation is implemented. Not yet. // TODO Include corelib analysis buildTests('testLibrary005', '''var PHI;main(){PHI=5.3;PHI.abs().!1 Object x;}''', ['1+abs'], failingTests: '1'); // Exercise import and export handling. // Libraries are defined in partial order of increasing dependency. sources.clear(); sources['/exp2a.dart'] = ''' library exp2a; e2a() {}'''; sources['/exp1b.dart'] = ''' library exp1b;", e1b() {}'''; sources['/exp1a.dart'] = ''' library exp1a;", export 'exp1b.dart';", e1a() {}'''; sources['/imp1.dart'] = ''' library imp1; export 'exp1a.dart'; i1() {}'''; sources['/imp2.dart'] = ''' library imp2; export 'exp2a.dart'; i2() {}'''; buildTests( 'testLibrary006', ''' import 'imp1.dart'; import 'imp2.dart'; main() {!1 i1(); i2(); e1a(); e1b(); e2a(); }''', ['1+i1', '1+i2', '1+e1a', '1+e2a', '1+e1b'], extraFiles: sources, failingTests: '1'); // Exercise import and export handling. // Libraries are defined in partial order of increasing dependency. sources.clear(); sources['/l1.dart'] = ''' library l1; var _l1t; var l1t;'''; buildTests( 'testLibrary007', ''' import 'l1.dart'; main() { var x = l!1 var y = _!2 }''', ['1+l1t', '1-_l1t', '2-_l1t'], extraFiles: sources, failingTests: '1'); // Check private library exclusion sources.clear(); sources['/public.dart'] = ''' library public; class NonPrivate { void publicMethod() { } }'''; sources['/private.dart'] = ''' library _private; import 'public.dart'; class Private extends NonPrivate { void privateMethod() { } }'''; buildTests( 'testLibrary008', ''' import 'private.dart'; import 'public.dart'; class Test { void test() { NonPrivate x = new NonPrivate(); x.!1 //publicMethod but not privateMethod should appear } }''', ['1-privateMethod', '1+publicMethod'], extraFiles: sources, failingTests: '1'); // Exercise library prefixes. sources.clear(); sources['/lib.dart'] = ''' library lib; int X = 1; void m(){} class Y {}'''; buildTests( 'testLibrary009', ''' import 'lib.dart' as Q; void a() { var x = Q.!1 } void b() { var x = [Q.!2] } void c() { var x = new List.filled([Q.!3], null) } void d() { new Q.!4 }''', [ '1+X', '1+m', '1+Y', '2+X', '2+m', '2+Y', '3+X', '3+m', '3+Y', '4+Y', '4-m', '4-X' ], extraFiles: sources, failingTests: '1234'); } void buildNumberedTests() { buildTests('test001', ''' void r1(var v) { v.!1toString!2().!3hash!4Code }''', [ '1+toString', '1-==', '2+toString', '3+hashCode', '3+toString', '4+hashCode', '4-toString' ]); buildTests('test002', ''' void r2(var vim) { v!1.toString() }''', ['1+vim']); buildTests('test003', ''' class A { int a() => 3; int b() => this.!1a(); }''', ['1+a']); buildTests( 'test004', ''' class A { int x; A() : this.!1x = 1; A.b() : this(); A.c() : this.!2b(); g() => new A.!3c(); }''', ['1+x', '2+b', '3+c'], failingTests: '12'); buildTests( 'test005', ''' class A {} void rr(var vim) { var !1vq = v!2.toString(); var vf; v!3.toString(); }''', [ '1-A', '1-vim', '1+vq', '1-vf', '1-this', '1-void', '1-null', '1-false', '2-A', '2+vim', '2-vf', '2-vq', '2-this', '2-void', '2-null', '2-false', '3+vf', '3+vq', '3+vim', '3-A' ], failingTests: '1'); buildTests('test006', ''' void r2(var vim, {va: 2, b: 3}) { v!1.toString() }''', ['1+va', '1-b']); buildTests('test007', ''' void r2(var vim, [va: 2, b: 3]) { v!1.toString() }''', ['1+va', '1-b']); // keywords buildTests( 'test008', ''' !1class Aclass {} class Bclass !2extends!3 !4Aclass {} !5abstract class Eclass implements Aclass, Bclass {} class Fclass extends Bclass !6with !7 Eclass {}''', [ '1+class', '1-implements', '1-extends', '1-with', '2+extends', '3+extends', '4+Aclass', '4-Bclass', '5+abstract', '6+with', '7+Eclass', '7-Dclass', '7-Ctype', ], failingTests: '2346'); // keywords buildTests( 'test009', ''' typedef !1dy!2namic TestFn1(); typedef !3vo!4id TestFn2(); typ!7edef !5n!6''', [ '1+void', '1+TestFn2', '2+dynamic', '2-void', '3+dynamic', '4+void', '4-dynamic', '5+TestFn2', '6+num', '7+typedef' ], failingTests: '1234'); buildTests( 'test010', ''' class test !8!7 {} class tezetst !9!A {}''', [ '1-String', '1-List', '1-test', '2-String', '2-test', '3+extends', '4-tezetst', '4-test', '5-String', '6-List', '7-List', '8-List', '9-String', 'A-String', 'B-String', 'C-List', 'C-tezetst', 'D-List', 'D-test' ], failingTests: '23'); // name generation with conflicts buildTests('test011', '''r2(var object, Object object1, Object !1);''', ['1+object2'], failingTests: '1'); // reserved words buildTests( 'test012', ''' class X { f() { g(!1var!2 z) {!3true.!4toString();}; } }''', [ '1+var', '1+dynamic', '1-f', '2+var', '2-dynamic', '3+false', '3+true', '4+toString' ], failingTests: '123'); // conditions & operators buildTests( 'test013', ''' class Q { bool x; List zs; int k; var a; mth() { while (!1x !9); do{} while(!2x !8); for(z in !3zs) {} switch(!4k) {case 1:{!0}} try { } on !5Object catch(a){} if (!7x !6) {} else {}; } }''', [ '1+x', '2+x', '3+zs', '4+k', '5+Q', '5-a', '6+==', '7+x', '8+==', '9+==', '0+k' ], failingTests: '689'); // keywords buildTests( 'test014', ''' class Q { bool x; List zs; int k; !Dvar a; !Evoid mth() { !1while (z) { !Gcontinue; }; !2do{ !Hbreak; } !3while(x); !4for(z !5in zs) {} !6for (int i; i < 3; i++); !7switch(k) {!8case 1:{} !9default:{}} !Atry { } !Bon Object !Ccatch(a){} !Fassert true; !Jif (x) {} !Kelse {}; !Lreturn; } }''', [ '1+while', '2+do', '3+while', '4+for', '5+in', '6+for', '7+switch', '8+case', '9+default:', 'A+try', 'B+on', 'C+catch', 'D+var', 'E+void', 'F+assert', 'G+continue', 'H+break', 'J+if', 'K+else', 'L+return' ], failingTests: '3CK'); // operators in function buildTests('test015', '''f(a,b,c) => a + b * c !1;''', ['1+=='], failingTests: '1'); // operators in return buildTests( 'test016', '''class X {dynamic f(a,b,c) {return a + b * c !1;}}''', ['1+=='], failingTests: '1'); // keywords buildTests( 'test017', ''' !1!2import 'x' !5as r; !3export '!8uri' !6hide Q !7show X; !4part 'x';''', [ '1+library', "2+import \'\';", "3+export \'\';", "4+part \'\';", '5+as', '6+hide', '7+show', '8-null' ], failingTests: '234567'); //TODO(jwren) 234 failing as correct selection // offset assertions can't be passed into buildTests(..) // keywords buildTests('test018', '''!1part !2of foo;''', ['1+part', '2+of'], failingTests: '12'); buildTests('test019', ''' var truefalse = 0; var falsetrue = 1; main() { var foo = true!1 }''', ['1+true', '1+truefalse', '1-falsetrue']); buildTests('test020', '''var x = null.!1''', ['1+toString']); buildTests('test021', '''var x = .!1''', ['1-toString']); buildTests('test022', '''var x = .!1;''', ['1-toString']); buildTests('test023', ''' class Map{getKeys(){}} class X { static x1(Map m) { m.!1getKeys; } x2(Map m) { m.!2getKeys; } }''', ['1+getKeys', '2+getKeys']); // Note lack of semicolon following completion location buildTests('test024', ''' class List{factory List.from(Iterable other) {}} class F { f() { new List.!1 } }''', ['1+from']); buildTests('test025', ''' class R { static R _m; static R m; f() { var a = !1m; var b = _!2m; var c = !3g(); } static g() { var a = !4m; var b = _!5m; var c = !6g(); } } class T { f() { R x; x.!7g(); x.!8m; x._!9m; } static g() { var q = R._!Am; var g = R.!Bm; var h = R.!Cg(); } h() { var q = R._!Dm; var g = R.!Em; var h = R.!Fg(); } }''', [ '1+m', '2+_m', '3+g', '4+m', '5+_m', '6+g', '7-g', '8-m', '9-_m', 'A+_m', 'B+m', 'C+g', 'D+_m', 'E+m', 'F+g' ]); buildTests('test026', '''var aBcD; var x=ab!1''', ['1+aBcD']); buildTests( 'test027', '''m(){try{}catch(eeee,ssss){s!1}''', ['1+ssss']); // https://github.com/dart-lang/sdk/issues/33992 buildTests('test028', '''m(){var isX=3;if(is!1)''', ['1+isX'], failingTests: '1'); buildTests('test029', '''m(){[1].forEach((x)=>!1x);}''', ['1+x']); buildTests('test030', '''n(){[1].forEach((x){!1});}''', ['1+x']); buildTests( 'test031', '''class Caster {} m() {try {} on Cas!1ter catch (CastBlock) {!2}}''', ['1+Caster', '1-CastBlock', '2+Caster', '2+CastBlock']); buildTests('test032', ''' const ONE = 1; const ICHI = 10; const UKSI = 100; const EIN = 1000; m() { int x; switch (x) { case !3ICHI: case UKSI: case EIN!2: case ONE!1: return; default: return; } }''', [ '1+ONE', '1-UKSI', '2+EIN', '2-ICHI', '3+ICHI', '3+UKSI', '3+EIN', '3+ONE' ]); buildTests( 'test033', '''class A{}class B extends A{b(){}}class C implements A {c(){}}class X{x(){A f;f.!1}}''', ['1+b', '1-c'], failingTests: '1'); // TODO(scheglov) decide what to do with Type for untyped field (not // supported by the new store) // test analysis of untyped fields and top-level vars buildTests( 'test034', ''' var topvar; class Top {top(){}} class Left extends Top {left(){}} class Right extends Top {right(){}} t1() { topvar = new Left(); } t2() { topvar = new Right(); } class A { var field; a() { field = new Left(); } b() { field = new Right(); } test() { topvar.!1top(); field.!2top(); } }''', ['1+top', '2+top'], failingTests: '12'); // test analysis of untyped fields and top-level vars buildTests('test035', '''class Y {final x='hi';mth() {x.!1length;}}''', ['1+length']); // TODO(scheglov) decide what to do with Type for untyped field (not // supported by the new store) // test analysis of untyped fields and top-level vars buildTests( 'test036', ''' class A1 { var field; A1() : field = 0; q() { A1 a = new A1(); a.field.!1 } } main() { A1 a = new A1(); a.field.!2 }''', ['1+round', '2+round'], failingTests: '12'); buildTests( 'test037', ''' class HttpServer{} class HttpClient{} main() { new HtS!1 }''', ['1+HttpServer', '1-HttpClient'], failingTests: '1'); buildTests('test038', ''' class X { x(){} } class Y { y(){} } class A { Y ay; Z az; A(this.ay, this.az) { ay.!1y; az.!2x; } }''', ['1+y', '1-x', '2+x', '2-y']); // test analysis of untyped fields and top-level vars buildTests( 'test039', '''class X{}var x = null as !1X;''', ['1-void']); // test arg lists with named params buildTests('test040', '''m(){f(a, b, {x1, x2, y}) {};f(1, 2, !1)!2;}''', ['1+x1', '2-x2'], failingTests: '1'); // test arg lists with named params buildTests('test041', '''m(){f(a, b, {x1, x2, y}) {};f(1, 2, !1''', ['1+x1', '1+x2', '1+y'], failingTests: '1'); // test arg lists with named params buildTests('test042', '''m(){f(a, b, {x1, x2, y}) {};f(1, 2, !1;!2''', ['1+x1', '1+x2', '2-y'], failingTests: '1'); } void buildOtherTests() { buildTests('test_classMembers_inGetter', '''class A { var fff; get z {ff!1}}''', ['1+fff']); buildTests( 'testSingle', '''class A {int x; !2mth() {int y = this.x;}}class B{}''', ['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. void buildTests(String baseName, String originalSource, List results, {Map? extraFiles, String failingTests = ''}) { var completionTests = LocationSpec.from(originalSource, results); completionTests.sort((LocationSpec first, LocationSpec second) { return first.id.compareTo(second.id); }); if (completionTests.isEmpty) { test(baseName, () { fail("Expected exclamation point ('!') within the source denoting the" 'position at which code completion should occur'); }); } var allSpecIds = completionTests.map((LocationSpec spec) => spec.id).toSet(); for (var id in failingTests.split('')) { if (!allSpecIds.contains(id)) { test('$baseName-$id', () { fail( "Test case '$id' included in failingTests, but this id does not exist."); }); } } for (var spec in completionTests) { var testName = '$baseName-${spec.id}'; if (failingTests.contains(spec.id)) { ++expectedFailCount; test('$testName (expected failure $expectedFailCount)', () { var test = CompletionTestCase(); expect( () => test.runTest(spec, extraFiles), throwsA(anything), ); }); } else { ++expectedPassCount; test(testName, () { var test = CompletionTestCase(); return test.runTest(spec, extraFiles); }); } } } }