| // 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;}}''', |
| <String>['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);}}''', |
| <String>['1+length', '2+x', '3+n']); |
| |
| buildTests('testCommentSnippets004', ''' |
| class A {!1int x; !2mth() {!3int y = this.!5x!6;}}class B{}''', |
| <String>['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; }}''', |
| <String>['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{}''', |
| <String>['1+bool', '2+bool', '3+int', '4+Arrays']); |
| |
| buildTests('testCommentSnippets008', ''' |
| class Date{}final num M = Dat!1''', <String>['1+Date']); |
| |
| // space, char, eol are important |
| buildTests( |
| 'testCommentSnippets009', |
| ''' |
| class Maps{}class x extends!5 !2M!3 !4implements!6 !1\n{}''', |
| <String>[ |
| '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{}''', <String>['1+Map']); |
| |
| // space, char, eol are important |
| buildTests('testCommentSnippets011', ''' |
| class x implements M!1{}''', <String>['1+Map']); |
| |
| // space, char, eol are important |
| buildTests('testCommentSnippets012', ''' |
| class x implements M!1\n{}''', <String>['1+Map']); |
| |
| buildTests('testCommentSnippets013', ''' |
| class x !2{!1}!3''', <String>['1+num', '2-num', '3+num']); |
| |
| // trailing space is important |
| buildTests('testCommentSnippets014', ''' |
| typedef n!1 ;''', <String>['1+num']); |
| |
| buildTests('testCommentSnippets015', ''' |
| class D {f(){} g(){f!1(f!2);}}''', <String>['1+f', '2+f']); |
| |
| buildTests('testCommentSnippets016', ''' |
| class F {m() { m(); !1}}''', <String>['1+m']); |
| |
| buildTests('testCommentSnippets017', ''' |
| class F {var x = !1false;}''', <String>['1+true']); |
| |
| buildTests('testCommentSnippets018', ''' |
| class Map{}class Arrays{}class C{ m(!1){} n(!2 x, q)''', <String>[ |
| '1+Map', |
| '1+dynamic', |
| '1+void', |
| '1-null', |
| '2+Arrays', |
| '2+void', |
| '2-null' |
| ]); |
| |
| buildTests('testCommentSnippets019', ''' |
| class A{m(){Object x;x.!1/**/clear()''', <String>['1+toString']); |
| |
| buildTests('testCommentSnippets020', ''' |
| classMap{}class tst {var newt;void newf(){}test() {var newz;new!1/**/;}}''', |
| <String>['1+newt', '1+newf', '1+newz', '1-Map']); |
| |
| buildTests('testCommentSnippets021', ''' |
| class Map{}class tst {var newt;void newf(){}test() {var newz;new !1/**/;}}''', |
| <String>['1+Map', '1-newt']); |
| |
| buildTests('testCommentSnippets022', ''' |
| class Map{}class F{m(){new !1;}}''', <String>['1+Map']); |
| |
| buildTests('testCommentSnippets022a', ''' |
| class Map{}class F{m(){new !1''', <String>['1+Map']); |
| |
| buildTests('testCommentSnippets022b', ''' |
| class Map{factory Map.qq(){return null;}}class F{m(){new Map.!1qq();}}''', |
| <String>['1+qq']); |
| |
| buildTests('testCommentSnippets023', ''' |
| class X {X c; X(this.!1c!3) : super() {c.!2}}''', |
| <String>['1+c', '2+c', '3+c']); |
| |
| buildTests('testCommentSnippets024', ''' |
| class q {m(Map q){var x;m(!1)}n(){var x;n(!2)}}''', <String>['1+x', '2+x']); |
| |
| buildTests('testCommentSnippets025', ''' |
| class C {num m() {var q; num x=!1 q!3 + !2/**/;}}''', |
| <String>['1+q', '2+q', '3+q']); |
| |
| buildTests('testCommentSnippets026', ''' |
| class List{}class a implements !1{}''', <String>['1+List']); |
| |
| buildTests('testCommentSnippets027', ''' |
| class String{}class List{}class test <X extends !1String!2> {}''', |
| <String>['1+List', '2+String', '2-List']); |
| |
| buildTests('testCommentSnippets028', ''' |
| class String{}class List{}class DateTime{}typedef T Y<T extends !1>(List input);''', |
| <String>['1+DateTime', '1+String']); |
| |
| buildTests('testCommentSnippets029', ''' |
| interface A<X> default B<X extends !1List!2> {}''', |
| <String>['1+DateTime', '2+List']); |
| |
| buildTests('testCommentSnippets030', ''' |
| class Bar<T extends Foo> {const Bar(!1T!2 k);T!3 m(T!4 a, T!5 b){}final T!6 f = null;}''', |
| <String>['1+T', '2+T', '3+T', '4+T', '5+T', '6+T']); |
| |
| buildTests('testCommentSnippets031', ''' |
| class Bar<T extends Foo> {m(x){if (x is !1) return;if (x is!!!2)}}''', |
| <String>['1+Bar', '1+T', '2+T', '2+Bar']); |
| |
| buildTests( |
| 'testCommentSnippets032', |
| ''' |
| class Fit{}class Bar<T extends Fooa> {const !2F!1ara();}''', |
| <String>['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);}}''', |
| <String>['1+add', '1+length']); |
| |
| // Type propagation |
| buildTests('testCommentSnippets035', ''' |
| class List{clear(){}length(){}}t3() {var x=[], y=x.!1length();x.!2clear();}''', |
| <String>['1+length', '2+clear']); |
| |
| buildTests('testCommentSnippets036', ''' |
| class List{}t3() {var x=new List!1}''', <String>['1+List']); |
| |
| buildTests('testCommentSnippets037', ''' |
| class List{factory List.from(){}}t3() {var x=new List.!1}''', |
| <String>['1+from']); |
| |
| buildTests('testCommentSnippets038', ''' |
| f(){int xa; String s = '\$x!1';}''', <String>['1+xa']); |
| |
| buildTests('testCommentSnippets038a', ''' |
| int xa; String s = '\$x!1\'''', <String>['1+xa']); |
| |
| buildTests('testCommentSnippets039', ''' |
| f(){int xa; String s = '\$!1';}''', <String>['1+xa']); |
| |
| buildTests('testCommentSnippets039a', ''' |
| int xa; String s = '\$!1\'''', <String>['1+xa']); |
| |
| buildTests('testCommentSnippets040', ''' |
| class List{add(){}}class Map{}class X{m(){List list; list.!1 Map map;}}''', |
| <String>['1+add']); |
| |
| buildTests('testCommentSnippets041', ''' |
| class List{add(){}length(){}}class X{m(){List list; list.!1 zox();}}''', |
| <String>['1+add']); |
| |
| buildTests('testCommentSnippets042', ''' |
| class DateTime{static const int WED=3;int get day;}fd(){DateTime d=new DateTime.now();d.!1WED!2;}''', |
| <String>['1+day', '2-WED']); |
| |
| buildTests('testCommentSnippets043', ''' |
| class L{var k;void.!1}''', <String>['1-k']); |
| |
| buildTests('testCommentSnippets044', ''' |
| class List{}class XXX {XXX.fisk();}void f() {f(); new !1}}''', |
| <String>['1+List', '1+XXX.fisk']); |
| |
| buildTests('testCommentSnippets045', ''' |
| class List{}class XXX {XXX.fisk();}void f() {f(); !1}}''', |
| <String>['1+List', '1+XXX.fisk']); |
| |
| buildTests('testCommentSnippets047', ''' |
| f(){int x;int y=!1;}''', <String>['1+x']); |
| |
| buildTests('testCommentSnippets048', ''' |
| import 'dart:convert' as json;f() {var x=new js!1}''', <String>['1+json']); |
| |
| buildTests('testCommentSnippets049', ''' |
| import 'dart:convert' as json; |
| import 'dart:convert' as jxx; |
| class JsonDecoderX{} |
| f1() {var x=new !2j!1s!3}''', <String>[ |
| '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); |
| }''', <String>[ |
| '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; |
| } |
| }''', <String>['1+length', '2-getKeys']); |
| |
| // Type propagation. |
| buildTests('testCommentSnippets052', ''' |
| class String{int length(){} String toUpperCase(){} bool isEmpty(){}}class Map{getKeys(){}} |
| void r() { |
| List<String> values = ['a','b','c']; |
| for (var v in values) { |
| v.!1toUpperCase; |
| v.!2getKeys; |
| } |
| }''', <String>['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; |
| } |
| }''', <String>['1+toUpperCase']); |
| |
| buildTests( |
| 'testCommentSnippets058', |
| ''' |
| typedef vo!2id callback(int k); |
| void x(callback q){} |
| void r() { |
| callback v; |
| x(!1); |
| }''', |
| <String>['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 |
| } |
| }''', <String>['1+x', '1-x[]']); |
| |
| buildTests('testCommentSnippets061', ''' |
| class A{m(){!1f(3);!2}}n(){!3f(3);!4}f(x)=>x*3;''', |
| <String>['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; |
| } |
| }''', <String>[ |
| '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; |
| } |
| }''', <String>['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; |
| } |
| }''', <String>['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; |
| } |
| }''', <String>['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; |
| } |
| }''', <String>['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; |
| } |
| }''', <String>['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; |
| } |
| }''', <String>['1+b']); |
| |
| buildTests('testCommentSnippets072', ''' |
| class X { |
| int _p; |
| set p(int x) => _p = x; |
| } |
| f() { |
| X x = new X(); |
| x.!1p = 3; |
| }''', <String>['1+p']); |
| |
| buildTests('testCommentSnippets073', ''' |
| class X { |
| m() { |
| JSON.stri!1; |
| X f = null; |
| } |
| } |
| class JSON { |
| static stringify() {} |
| }''', <String>['1+stringify']); |
| |
| buildTests('testCommentSnippets074', ''' |
| class X { |
| m() { |
| _x!1 |
| } |
| _x1(){} |
| }''', <String>['1+_x1']); |
| |
| buildTests('testCommentSnippets075', ''' |
| p(x)=>0;var E;f(q)=>!1p(!2E);''', <String>['1+p', '2+E']); |
| |
| buildTests('testCommentSnippets076', ''' |
| class Map<K,V>{}class List<E>{}class int{}void f() {var m=new Map<Lis!1t<Map<int,in!2t>>,List<!3int>>();}''', |
| <String>['1+List', '2+int', '3+int']); |
| |
| buildTests('testCommentSnippets076a', ''' |
| class Map<K,V>{}class List<E>{}class int{}void f() {var m=new Map<Lis!1t<Map<int,in!2t>>,List<!3>>();}''', |
| <String>['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''', <String>[ |
| '1+File', |
| '1+File.fromPath', |
| '1+FileMode', |
| '1+FileMode._internal1', |
| '1+FileMode._internal' |
| ]); |
| |
| buildTests('testCommentSnippets078', ''' |
| class Map{static from()=>null;clear(){}}void f() { Map.!1 }''', |
| <String>['1+from', '1-clear']); // static method, instance method |
| |
| buildTests('testCommentSnippets079', ''' |
| class Map{static from()=>null;clear(){}}void f() { Map s; s.!1 }''', |
| <String>['1-from', '1+clear']); // static method, instance method |
| |
| buildTests('testCommentSnippets080', ''' |
| class RuntimeError{var message;}void f() { RuntimeError.!1 }''', |
| <String>['1-message']); // field |
| |
| buildTests( |
| 'testCommentSnippets081', |
| ''' |
| class Foo {this.!1}''', |
| <String>['1-Object'], |
| failingTests: '1'); |
| |
| // https://github.com/dart-lang/sdk/issues/33992 |
| buildTests( |
| 'testCommentSnippets082', |
| ''' |
| class HttpRequest {} |
| class HttpResponse {} |
| void f() { |
| var v = (HttpRequest req, HttpResp!1) |
| }''', |
| <String>['1+HttpResponse'], |
| failingTests: '1'); |
| |
| buildTests('testCommentSnippets083', ''' |
| void f() {(.!1)}''', <String>['1-toString']); |
| |
| buildTests('testCommentSnippets083a', ''' |
| void f() { .!1 }''', <String>['1-toString']); |
| |
| buildTests('testCommentSnippets083b', ''' |
| void f() { null.!1 }''', <String>['1+toString']); |
| |
| buildTests('testCommentSnippets085', ''' |
| class List{}class Map{}class Z extends List with !1Ma!2p {}''', |
| <String>['1+List', '1+Map', '2+Map', '2-List']); |
| |
| buildTests( |
| 'testCommentSnippets086', |
| ''' |
| class Q{f(){xy() {!2};x!1y();}}''', |
| <String>['1+xy', '2+f', '2-xy'], |
| failingTests: '2'); |
| |
| buildTests('testCommentSnippets087', ''' |
| class Map{}class Q extends Object with !1Map {}''', |
| <String>['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} |
| }''', <String>['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 |
| } |
| }''', |
| <String>[ |
| '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 }}''', <String>['1+length']); |
| } |
| |
| void buildCompletionTests() { |
| buildTests('testCompletion_alias_field', ''' |
| typedef int fnint(int k); fn!1int x;''', <String>['1+fnint']); |
| |
| buildTests( |
| 'testCompletion_annotation_argumentList', |
| ''' |
| class AAA {", |
| const AAA({int aaa, int bbb});", |
| }", |
| ", |
| @AAA(!1) |
| void f() { |
| }''', |
| <String>[ |
| '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 |
| void f() { |
| }''', |
| <String>['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 |
| void f() { |
| }''', <String>[ |
| '1+AAA' /*":" + ProposalKind.CONSTRUCTOR*/, |
| '1+AAA.nnn' /*":" + ProposalKind.CONSTRUCTOR*/ |
| ]); |
| |
| buildTests('testCompletion_annotation_type_inClass_withoutMember', ''' |
| class AAA { |
| const AAA(); |
| } |
| |
| class C { |
| @A!1 |
| }''', <String>[ |
| '1+AAA' /*":" + ProposalKind.CONSTRUCTOR*/ |
| ]); |
| |
| buildTests('testCompletion_argument_typeName', ''' |
| class Enum { |
| static Enum FOO = new Enum(); |
| } |
| f(Enum e) {} |
| void f() { |
| f(En!1); |
| }''', <String>['1+Enum']); |
| |
| buildTests('testCompletion_arguments_ignoreEmpty', ''' |
| class A { |
| test() {} |
| } |
| void f(A a) { |
| a.test(!1); |
| }''', <String>['1-test']); |
| |
| buildTests('testCompletion_as_asIdentifierPrefix', ''' |
| void f(p) { |
| var asVisible; |
| var v = as!1; |
| }''', <String>['1+asVisible']); |
| |
| buildTests('testCompletion_as_asPrefixedIdentifierStart', ''' |
| class A { |
| var asVisible; |
| } |
| |
| void f(A p) { |
| var v = p.as!1; |
| }''', <String>['1+asVisible']); |
| |
| buildTests('testCompletion_as_incompleteStatement', ''' |
| class MyClass {} |
| void f(p) { |
| var justSomeVar; |
| var v = p as !1 |
| }''', <String>['1+MyClass', '1-justSomeVar']); |
| |
| buildTests('testCompletion_cascade', ''' |
| class A { |
| aaa() {} |
| } |
| |
| |
| void f(A a) { |
| a..!1 aaa(); |
| }''', <String>['1+aaa', '1-f']); |
| |
| buildTests('testCompletion_combinator_afterComma', ''' |
| import 'dart:math' show cos, !1;''', |
| <String>['1+pi', '1+sin', '1+Random', '1-String']); |
| |
| buildTests('testCompletion_combinator_ended', ''' |
| import 'dart:math' show !1;"''', |
| <String>['1+pi', '1+sin', '1+Random', '1-String']); |
| |
| buildTests('testCompletion_combinator_export', ''' |
| export 'dart:math' show !1;"''', |
| <String>['1+pi', '1+sin', '1+Random', '1-String']); |
| |
| buildTests('testCompletion_combinator_hide', ''' |
| import 'dart:math' hide !1;"''', |
| <String>['1+pi', '1+sin', '1+Random', '1-String']); |
| |
| buildTests('testCompletion_combinator_notEnded', ''' |
| import 'dart:math' show !1"''', |
| <String>['1+pi', '1+sin', '1+Random', '1-String']); |
| |
| buildTests('testCompletion_combinator_usePrefix', ''' |
| import 'dart:math' show s!1"''', |
| <String>['1+sin', '1+sqrt', '1-cos', '1-String']); |
| |
| buildTests( |
| 'testCompletion_constructor_field', |
| ''' |
| class X { X(this.field); int f!1ield;}''', |
| <String>['1+field'], |
| failingTests: '1'); |
| |
| buildTests( |
| 'testCompletion_constructorArguments_showOnlyCurrent', |
| ''' |
| class A { |
| A.first(int p); |
| A.second(double p); |
| } |
| void f() { |
| new A.first(!1); |
| }''', |
| <String>['1+A.first', '1-A.second'], |
| failingTests: '1'); |
| |
| buildTests( |
| 'testCompletion_constructorArguments_whenPrefixedType', |
| ''' |
| import 'dart:math' as m; |
| void f() { |
| new m.Random(!1); |
| }''', |
| <String>['1+Random:ARGUMENT_LIST'], |
| failingTests: '1'); |
| |
| buildTests('testCompletion_dartDoc_reference_forClass', ''' |
| /** |
| * [int!1] |
| * [method!2] |
| */ |
| class AAA { |
| methodA() {} |
| }''', <String>['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() {} |
| }''', <String>['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() {}''', |
| <String>[ |
| '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() {}''', |
| <String>[ |
| '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() {} |
| }''', <String>[ |
| '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 {}''', <String>[ |
| '1+double', |
| '1-int', |
| '2+int', |
| '2+String', |
| '3+int', |
| '3+String' |
| ]); |
| |
| buildTests('testCompletion_double_inFractionPart', ''' |
| void f() { |
| 1.0!1 |
| }''', <String>['1-abs', '1-f']); |
| |
| buildTests('testCompletion_enum', ''' |
| enum MyEnum {A, B, C} |
| void f() { |
| MyEnum.!1; |
| }''', <String>['1+values', '1+A', '1+B', '1+C']); |
| |
| buildTests('testCompletion_exactPrefix_hasHigherRelevance', ''' |
| var STR; |
| void f(p) { |
| var str; |
| str!1; |
| STR!2; |
| Str!3; |
| }''', <String>[ |
| '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''', <String>[ |
| '1+dart:core', |
| '1+dart:math', |
| '1-dart:_collection.dev', |
| ]); |
| |
| buildTests( |
| 'testCompletion_export_noStringLiteral_noSemicolon', |
| ''' |
| import !1 |
| |
| class A {}''', |
| <String>["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++); }}''', |
| <String>['1+int', '2+i', '3+i']); |
| |
| buildTests('testCompletion_function', ''' |
| class Foo { int boo = 7; mth() { PNGS.sort((String a, Str!1) => a.compareTo(b)); }}''', |
| <String>['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)); }}''', |
| <String>['1+String'], |
| failingTests: '1'); |
| |
| buildTests( |
| 'testCompletion_functionTypeParameter_namedArgument', |
| ''' |
| typedef FFF(a, b, {x1, x2, y}); |
| void f(FFF fff) { |
| fff(1, 2, !1)!2; |
| }''', |
| <String>['1+x1', '2-x2'], |
| failingTests: '1'); |
| |
| buildTests('testCompletion_ifStmt_field1', ''' |
| class Foo { int myField = 7; mth() { if (!1) {}}}''', <String>['1+myField']); |
| |
| buildTests('testCompletion_ifStmt_field1a', ''' |
| class Foo { int myField = 7; mth() { if (!1) }}''', <String>['1+myField']); |
| |
| buildTests('testCompletion_ifStmt_field2', ''' |
| class Foo { int myField = 7; mth() { if (m!1) {}}}''', <String>['1+myField']); |
| |
| buildTests('testCompletion_ifStmt_field2a', ''' |
| class Foo { int myField = 7; mth() { if (m!1) }}''', <String>['1+myField']); |
| |
| buildTests('testCompletion_ifStmt_field2b', ''' |
| class Foo { myField = 7; mth() { if (m!1) {}}}''', <String>['1+myField']); |
| |
| buildTests('testCompletion_ifStmt_localVar', ''' |
| class Foo { mth() { int value = 7; if (v!1) {}}}''', <String>['1+value']); |
| |
| buildTests('testCompletion_ifStmt_localVara', ''' |
| class Foo { mth() { value = 7; if (v!1) {}}}''', <String>['1-value']); |
| |
| buildTests('testCompletion_ifStmt_topLevelVar', ''' |
| int topValue = 7; class Foo { mth() { if (t!1) {}}}''', <String>['1+topValue']); |
| |
| buildTests('testCompletion_ifStmt_topLevelVara', ''' |
| topValue = 7; class Foo { mth() { if (t!1) {}}}''', <String>['1+topValue']); |
| |
| buildTests( |
| 'testCompletion_ifStmt_unionType_nonStrict', |
| ''' |
| class A { a() => null; x() => null} |
| class B { a() => null; y() => null} |
| void f() { |
| var x; |
| var c; |
| if(c) { |
| x = new A(); |
| } else { |
| x = new B(); |
| } |
| x.!1; |
| }''', |
| <String>['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 f() { |
| var x; |
| var c; |
| if(c) { |
| x = new A(); |
| } else { |
| x = new B(); |
| } |
| x.!1; |
| }''', |
| <String>['1+a', '1-x', '1-y'], |
| failingTests: '1'); |
| |
| buildTests('testCompletion_import', ''' |
| import '!1';''', <String>['1+dart:!', '1+package:!']); |
| |
| buildTests('testCompletion_import_dart', ''' |
| import 'dart:math |
| import 'dart:_collection.dev |
| import 'dart:!1''', <String>[ |
| '1+dart:core', |
| '1+dart:math', |
| '1-dart:_collection.dev', |
| ]); |
| |
| buildTests('testCompletion_import_hasStringLiteral_noSemicolon', ''' |
| import '!1' |
| |
| class A {}''', <String>['1+dart:!', '1+package:!']); |
| |
| buildTests( |
| 'testCompletion_import_noSpace', |
| ''' |
| import!1''', |
| <String>["1+ 'dart:!';", "1+ 'package:!';"], |
| failingTests: '1'); |
| |
| buildTests( |
| 'testCompletion_import_noStringLiteral', |
| ''' |
| import !1;''', |
| <String>["1+'dart:!'", "1+'package:!'"], |
| failingTests: '1'); |
| |
| buildTests( |
| 'testCompletion_import_noStringLiteral_noSemicolon', |
| ''' |
| import !1 |
| |
| class A {}''', |
| <String>["1+'dart:!';", "1+'package:!';"], |
| failingTests: '1'); |
| |
| buildTests('testCompletion_incompleteClassMember', ''' |
| class A { |
| Str!1 |
| final f = null; |
| }''', <String>['1+String', '1-bool']); |
| |
| buildTests('testCompletion_incompleteClosure_parameterType', ''' |
| f1(cb(String s)) {} |
| f2(String s) {} |
| void f() { |
| f1((Str!1)); |
| f2((Str!2)); |
| }''', <String>['1+String', '1-bool', '2+String', '2-bool']); |
| |
| buildTests( |
| 'testCompletion_inPeriodPeriod', |
| ''' |
| void f(String str) { |
| 1 < str.!1.length; |
| 1 + str.!2.length; |
| 1 + 2 * str.!3.length; |
| }''', |
| <String>['1+codeUnits', '2+codeUnits', '3+codeUnits'], |
| failingTests: '123'); |
| |
| // no checks, but no exceptions |
| buildTests('testCompletion_instanceCreation_unresolved', ''' |
| class A { |
| } |
| void f() { |
| new NoSuchClass(!1); |
| new A.noSuchConstructor(!2); |
| }''', <String>['1+int', '2+int']); |
| |
| buildTests( |
| 'testCompletion_import_lib', |
| ''' |
| import '!1''', |
| <String>['1+my_lib.dart'], |
| extraFiles: <String, String>{'/my_lib.dart': ''}, |
| failingTests: '1'); |
| |
| buildTests('testCompletion_is', ''' |
| class MyClass {} |
| void f(p) { |
| var isVariable; |
| if (p is MyCla!1) {} |
| var v1 = p is MyCla!2; |
| var v2 = p is !3; |
| var v2 = p is!4; |
| }''', <String>[ |
| '1+MyClass', |
| '2+MyClass', |
| '3+MyClass', |
| '3-v1', |
| '4+is', |
| '4-isVariable' |
| ]); |
| |
| // https://github.com/dart-lang/sdk/issues/33992 |
| buildTests( |
| 'testCompletion_is_asIdentifierStart', |
| ''' |
| void f(p) { |
| var isVisible; |
| var v1 = is!1; |
| var v2 = is!2 |
| }''', |
| <String>['1+isVisible', '2+isVisible'], |
| failingTests: '12'); |
| |
| buildTests('testCompletion_is_asPrefixedIdentifierStart', ''' |
| class A { |
| var isVisible; |
| } |
| |
| void f(A p) { |
| var v1 = p.is!1; |
| var v2 = p.is!2 |
| }''', <String>['1+isVisible', '2+isVisible']); |
| |
| buildTests('testCompletion_is_incompleteStatement1', ''' |
| class MyClass {} |
| void f(p) { |
| var justSomeVar; |
| var v = p is !1 |
| }''', <String>['1+MyClass', '1-justSomeVar']); |
| |
| buildTests('testCompletion_is_incompleteStatement2', ''' |
| class MyClass {} |
| void f(p) { |
| var isVariable; |
| var v = p is!1 |
| }''', <String>['1+is', '1-isVariable']); |
| |
| buildTests('testCompletion_keyword_in', ''' |
| class Foo { int input = 7; mth() { if (in!1) {}}}''', <String>['1+input']); |
| |
| buildTests('testCompletion_keyword_syntheticIdentifier', ''' |
| void f() { |
| var caseVar; |
| var otherVar; |
| var v = case!1 |
| }''', <String>['1+caseVar', '1-otherVar']); |
| |
| buildTests('testCompletion_libraryIdentifier_atEOF', ''' |
| library int.!1''', <String>['1-parse', '1-bool']); |
| |
| buildTests('testCompletion_libraryIdentifier_notEOF', ''' |
| library int.!1''', <String>['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) {} |
| void f(p) { |
| foo( Functions.!1; ); |
| }''', |
| <String>[ |
| '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) {} |
| void f(p) { |
| foo( (int p) => Functions.!1; ); |
| }''', |
| <String>[ |
| '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) {} |
| } |
| void f(p) { |
| foo(Functions.!1); |
| }''', <String>[ |
| '1+myFunc' /*":" + ProposalKind.METHOD*/, |
| '1+myFunc' /*":" + ProposalKind.METHOD_NAME*/ |
| ]); |
| |
| buildTests('testCompletion_namedArgument_alreadyUsed', ''' |
| func({foo}) {} void f() { func(foo: 0, fo!1); }''', <String>['1-foo']); |
| |
| buildTests( |
| 'testCompletion_namedArgument_constructor', |
| ''' |
| class A {A({foo, bar}) {}} void f() { new A(fo!1); }''', |
| <String>['1+foo', '1-bar'], |
| failingTests: '1'); |
| |
| buildTests( |
| 'testCompletion_namedArgument_empty', |
| ''' |
| func({foo, bar}) {} void f() { func(!1); }''', |
| <String>[ |
| '1+foo' /*":" + ProposalKind.NAMED_ARGUMENT*/, |
| '1-foo' /*":" + ProposalKind.OPTIONAL_ARGUMENT*/ |
| ], |
| failingTests: '1'); |
| |
| buildTests( |
| 'testCompletion_namedArgument_function', |
| ''' |
| func({foo, bar}) {} void f() { func(fo!1); }''', |
| <String>['1+foo', '1-bar'], |
| failingTests: '1'); |
| |
| buildTests('testCompletion_namedArgument_notNamed', ''' |
| func([foo]) {} void f() { func(fo!1); }''', <String>['1-foo']); |
| |
| buildTests('testCompletion_namedArgument_unresolvedFunction', ''' |
| void f() { func(fo!1); }''', <String>['1-foo']); |
| |
| buildTests('testCompletion_newMemberType1', ''' |
| class Collection{}class List extends Collection{}class Foo { !1 }''', |
| <String>['1+Collection', '1+List']); |
| |
| buildTests('testCompletion_newMemberType2', ''' |
| class Collection{}class List extends Collection{}class Foo {!1}''', |
| <String>['1+Collection', '1+List']); |
| |
| buildTests('testCompletion_newMemberType3', ''' |
| class Collection{}class List extends Collection{}class Foo {L!1}''', |
| <String>['1-Collection', '1+List']); |
| |
| buildTests('testCompletion_newMemberType4', ''' |
| class Collection{}class List extends Collection{}class Foo {C!1}''', |
| <String>['1+Collection', '1-List']); |
| |
| buildTests( |
| 'testCompletion_positionalArgument_constructor', |
| ''' |
| class A { |
| A([foo, bar]); |
| } |
| void f() { |
| new A(!1); |
| new A(0, !2); |
| }''', |
| <String>[ |
| '1+foo' /*":" + ProposalKind.OPTIONAL_ARGUMENT*/, |
| '1-bar', |
| '2-foo', |
| '2+bar' /*":" |
| + ProposalKind.OPTIONAL_ARGUMENT*/ |
| ], |
| failingTests: '12'); |
| |
| buildTests( |
| 'testCompletion_positionalArgument_function', |
| ''' |
| func([foo, bar]) {} |
| void f() { |
| func(!1); |
| func(0, !2); |
| }''', |
| <String>[ |
| '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() {} |
| } |
| void f() { |
| A v = new B(); |
| v.!1 |
| }''', |
| <String>[ |
| '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(); |
| } |
| void f() { |
| new A.!1 |
| }''', <String>['1+_c', '1+c']); |
| |
| buildTests('testCompletion_privateElement_sameLibrary_member', ''' |
| class A { |
| _m() {} |
| m() {} |
| } |
| void f(A a) { |
| a.!1 |
| }''', <String>['1+_m', '1+m']); |
| |
| buildTests('testCompletion_propertyAccess_whenClassTarget', ''' |
| class A { |
| static int FIELD; |
| int field; |
| } |
| void f() { |
| A.!1 |
| }''', <String>['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() {} |
| } |
| void f() { |
| B.!1; |
| }''', <String>['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; |
| } |
| void f(B b, C c) { |
| b.a.!1; |
| c.!2; |
| }''', <String>['1-FIELD', '1+fieldA', '2+fieldC', '2+fieldA']); |
| |
| buildTests('testCompletion_return_withIdentifierPrefix', ''' |
| f() { var vvv = 42; return v!1 }''', <String>['1+vvv']); |
| |
| buildTests('testCompletion_return_withoutExpression', ''' |
| f() { var vvv = 42; return !1 }''', <String>['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 }}''', |
| <String>['1+MAX_D', 'X+xc', 'Y+yc', '2+num', '3+num', '4+Sunflower']); |
| |
| buildTests('testCompletion_staticField_withoutVarOrFinal', ''' |
| class num{}class Sunflower {static n!1}''', <String>['1+num']); |
| |
| buildTests('testCompletion_super_superType', ''' |
| class A { |
| var fa; |
| ma() {} |
| } |
| class B extends A { |
| var fb; |
| mb() {} |
| void f() { |
| super.!1 |
| } |
| }''', <String>['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 |
| }''', <String>['1+fooA', '1+fooB', '1+bar']); |
| |
| buildTests('testCompletion_superConstructorInvocation_withNamePrefix', ''' |
| class A { |
| A.fooA(); |
| A.fooB(); |
| A.bar(); |
| } |
| class B extends A { |
| B() : super.f!1 |
| }''', <String>['1+fooA', '1+fooB', '1-bar']); |
| |
| buildTests( |
| 'testCompletion_this_bad_inConstructorInitializer', |
| ''' |
| class A { |
| var f; |
| A() : f = this.!1; |
| }''', |
| <String>['1-toString'], |
| failingTests: '1'); |
| |
| buildTests( |
| 'testCompletion_this_bad_inFieldDeclaration', |
| ''' |
| class A { |
| var f = this.!1; |
| }''', |
| <String>['1-toString'], |
| failingTests: '1'); |
| |
| buildTests( |
| 'testCompletion_this_bad_inStaticMethod', |
| ''' |
| class A { |
| static m() { |
| this.!1; |
| } |
| }''', |
| <String>['1-toString'], |
| failingTests: '1'); |
| |
| buildTests( |
| 'testCompletion_this_bad_inTopLevelFunction', |
| ''' |
| void f() { |
| this.!1; |
| }''', |
| <String>['1-toString'], |
| failingTests: '1'); |
| |
| buildTests( |
| 'testCompletion_this_bad_inTopLevelVariableDeclaration', |
| ''' |
| var v = this.!1;''', |
| <String>['1-toString'], |
| failingTests: '1'); |
| |
| buildTests('testCompletion_this_OK_inConstructorBody', ''' |
| class A { |
| var f; |
| m() {} |
| A() { |
| this.!1; |
| } |
| }''', <String>['1+f', '1+m']); |
| |
| buildTests('testCompletion_this_OK_localAndSuper', ''' |
| class A { |
| var fa; |
| ma() {} |
| } |
| class B extends A { |
| var fb; |
| mb() {} |
| void m() { |
| this.!1 |
| } |
| }''', <String>['1+fa', '1+fb', '1+ma', '1+mb']); |
| |
| buildTests('testCompletion_topLevelField_init2', ''' |
| class DateTime{static var JUN;}final num M = Dat!1eTime.JUN;''', |
| <String>['1+DateTime', '1-void']); |
| |
| buildTests('testCompletion_while', ''' |
| class Foo { int boo = 7; mth() { while (b!1) {} }}''', <String>['1+boo']); |
| } |
| |
| void buildLibraryTests() { |
| Map<String, String> sources = HashMap<String, String>(); |
| |
| buildTests('test_export_ignoreIfThisLibraryExports', ''' |
| export 'dart:math'; |
| libFunction() {}; |
| void f() { |
| !1 |
| }''', <String>['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; |
| void f() { |
| p.!1 |
| }''', |
| <String>['1+cos', '1-sin', '1+libFunction'], |
| extraFiles: sources, |
| failingTests: '1'); |
| |
| buildTests('test_importPrefix_hideCombinator', ''' |
| import 'dart:math' as math hide pi; |
| void f() { |
| math.!1 |
| }''', <String>['1-pi', '1+ln10']); |
| |
| buildTests('test_importPrefix_showCombinator', ''' |
| import 'dart:math' as math show pi; |
| void f() { |
| math.!1 |
| }''', <String>['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'; |
| void f(A a) { |
| a.!1 |
| }''', |
| <String>['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'; |
| void f() { |
| new A.!1 |
| }''', |
| <String>['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'; |
| void f(A a) { |
| a.!1 |
| }''', |
| <String>['1-_f', '1+f'], |
| extraFiles: sources, |
| failingTests: '1'); |
| |
| sources.clear(); |
| sources['/firth.dart'] = ''' |
| library firth; |
| class SerializationException { |
| const SerializationException(); |
| }'''; |
| buildTests( |
| 'testLibrary001', |
| ''' |
| import 'firth.dart'; |
| void f() { |
| throw new Seria!1lizationException();}''', |
| <String>['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();}''', |
| <String>['1+length', '1+isEmpty', '2+clear']); |
| |
| // TODO Include corelib analysis |
| buildTests('testLibrary003', '''class X{var q; f() {q.!1a!2}}''', |
| <String>['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}''', <String>[ |
| '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;void f(){PHI=5.3;PHI.abs().!1 Object x;}''', |
| <String>['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'; |
| void f() {!1 |
| i1(); |
| i2(); |
| e1a(); |
| e1b(); |
| e2a(); |
| }''', |
| <String>['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'; |
| void f() { |
| var x = l!1 |
| var y = _!2 |
| }''', |
| <String>['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 |
| } |
| }''', |
| <String>['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 |
| }''', |
| <String>[ |
| '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 |
| }''', <String>[ |
| '1+toString', |
| '1-==', |
| '2+toString', |
| '3+hashCode', |
| '3+toString', |
| '4+hashCode', |
| '4-toString' |
| ]); |
| |
| buildTests('test002', ''' |
| void r2(var vim) { |
| v!1.toString() |
| }''', <String>['1+vim']); |
| |
| buildTests('test003', ''' |
| class A { |
| int a() => 3; |
| int b() => this.!1a(); |
| }''', <String>['1+a']); |
| |
| buildTests( |
| 'test004', |
| ''' |
| class A { |
| int x; |
| A() : this.!1x = 1; |
| A.b() : this(); |
| A.c() : this.!2b(); |
| g() => new A.!3c(); |
| }''', |
| <String>['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(); |
| }''', |
| <String>[ |
| '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() |
| }''', <String>['1+va', '1-b']); |
| |
| buildTests('test007', ''' |
| void r2(var vim, [va: 2, b: 3]) { |
| v!1.toString() |
| }''', <String>['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 {}''', |
| <String>[ |
| '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''', |
| <String>[ |
| '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<!1t !2 !3extends String,!4 List,!5 !6>!7 {} |
| class tezetst !9<!BString,!C !DList>!A {}''', |
| <String>[ |
| '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);''', |
| <String>['1+object2'], |
| failingTests: '1'); |
| |
| // reserved words |
| buildTests( |
| 'test012', |
| ''' |
| class X { |
| f() { |
| g(!1var!2 z) {!3true.!4toString();}; |
| } |
| }''', |
| <String>[ |
| '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 {}; |
| } |
| }''', |
| <String>[ |
| '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; |
| } |
| }''', |
| <String>[ |
| '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;''', <String>['1+=='], |
| failingTests: '1'); |
| |
| // operators in return |
| buildTests( |
| 'test016', |
| '''class X {dynamic f(a,b,c) {return a + b * c !1;}}''', |
| <String>['1+=='], |
| failingTests: '1'); |
| |
| // keywords |
| buildTests( |
| 'test017', |
| ''' |
| !1!2import 'x' !5as r; |
| !3export '!8uri' !6hide Q !7show X; |
| !4part 'x';''', |
| <String>[ |
| '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;''', <String>['1+part', '2+of'], |
| failingTests: '12'); |
| |
| buildTests('test019', ''' |
| var truefalse = 0; |
| var falsetrue = 1; |
| void f() { |
| var foo = true!1 |
| }''', <String>['1+true', '1+truefalse', '1-falsetrue']); |
| |
| buildTests('test020', '''var x = null.!1''', <String>['1+toString']); |
| |
| buildTests('test021', '''var x = .!1''', <String>['1-toString']); |
| |
| buildTests('test022', '''var x = .!1;''', <String>['1-toString']); |
| |
| buildTests('test023', ''' |
| class Map{getKeys(){}} |
| class X { |
| static x1(Map m) { |
| m.!1getKeys; |
| } |
| x2(Map m) { |
| m.!2getKeys; |
| } |
| }''', <String>['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 |
| } |
| }''', <String>['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(); |
| } |
| }''', <String>[ |
| '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''', <String>['1+aBcD']); |
| |
| buildTests( |
| 'test027', '''m(){try{}catch(eeee,ssss){s!1}''', <String>['1+ssss']); |
| |
| // https://github.com/dart-lang/sdk/issues/33992 |
| buildTests('test028', '''m(){var isX=3;if(is!1)''', <String>['1+isX'], |
| failingTests: '1'); |
| |
| buildTests('test029', '''m(){[1].forEach((x)=>!1x);}''', <String>['1+x']); |
| |
| buildTests('test030', '''n(){[1].forEach((x){!1});}''', <String>['1+x']); |
| |
| buildTests( |
| 'test031', |
| '''class Caster {} m() {try {} on Cas!1ter catch (CastBlock) {!2}}''', |
| <String>['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; |
| } |
| }''', <String>[ |
| '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}}''', |
| <String>['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(); |
| } |
| }''', |
| <String>['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;}}''', |
| <String>['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 |
| } |
| } |
| void f() { |
| A1 a = new A1(); |
| a.field.!2 |
| }''', |
| <String>['1+round', '2+round'], |
| failingTests: '12'); |
| |
| buildTests( |
| 'test037', |
| ''' |
| class HttpServer{} |
| class HttpClient{} |
| void f() { |
| new HtS!1 |
| }''', |
| <String>['1+HttpServer', '1-HttpClient'], |
| failingTests: '1'); |
| |
| buildTests('test038', ''' |
| class X { |
| x(){} |
| } |
| class Y { |
| y(){} |
| } |
| class A<Z extends X> { |
| Y ay; |
| Z az; |
| A(this.ay, this.az) { |
| ay.!1y; |
| az.!2x; |
| } |
| }''', <String>['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;''', <String>['1-void']); |
| |
| // test arg lists with named params |
| buildTests('test040', '''m(){f(a, b, {x1, x2, y}) {};f(1, 2, !1)!2;}''', |
| <String>['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''', |
| <String>['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''', |
| <String>['1+x1', '1+x2', '2-y'], |
| failingTests: '1'); |
| } |
| |
| void buildOtherTests() { |
| buildTests('test_classMembers_inGetter', |
| '''class A { var fff; get z {ff!1}}''', <String>['1+fff']); |
| |
| buildTests( |
| 'testSingle', |
| '''class A {int x; !2mth() {int y = this.x;}}class B{}''', |
| <String>['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<String> results, |
| {Map<String, String>? 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); |
| }); |
| } |
| } |
| } |
| } |