Skip to content

Commit 9e4cf6a

Browse files
committed
Add tests for static extension methods.
Change-Id: I385db23248d266ae69882f7fb13f1a1e8d7ed5d1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106908 Reviewed-by: Leaf Petersen <[email protected]> Reviewed-by: Erik Ernst <[email protected]>
1 parent 35fb237 commit 9e4cf6a

8 files changed

+1236
-0
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// SharedOptions=--enable-experiment=extension-methods
6+
7+
import "package:expect/expect.dart";
8+
9+
// Tests the syntax of extension methods, and that the extensions are
10+
// invocable, and that type variables are bound correctly.
11+
12+
// There are no extension *conflicts*.
13+
// For each invocation, there is exactly one extension member in scope
14+
// which applies.
15+
16+
// Target types.
17+
class Unnamed {}
18+
19+
class Named {}
20+
21+
class UnnamedGeneric<T> {}
22+
23+
class NamedGeneric<T> {}
24+
25+
String str(String name, Object object) =>
26+
"$name(${object == null ? "null" : "non-null"})";
27+
28+
// Unnamed local extension.
29+
extension on Unnamed {
30+
String get name => str("unnamed", this);
31+
}
32+
33+
extension NamedExt on Named {
34+
String get name => str("named", this);
35+
}
36+
37+
extension<T> on UnnamedGeneric<T> {
38+
String get name => str("unnamed generic", this);
39+
List<T> get list => <T>[];
40+
}
41+
42+
extension NamedGenericExt<T> on NamedGeneric<T> {
43+
String get name => str("named generic", this);
44+
List<T> get list => <T>[];
45+
}
46+
47+
extension General on Object {
48+
String get generalName => str("general", this);
49+
}
50+
51+
extension GeneralGeneric<T> on T {
52+
String get generalGenericName => str("general generic", this);
53+
List<T> get generalList => <T>[];
54+
}
55+
56+
main() {
57+
// Unnamed.
58+
Unnamed unnamed = Unnamed();
59+
Unnamed unnamedNull = null;
60+
61+
Expect.equals("unnamed(non-null)", unnamed.name);
62+
Expect.equals("unnamed(null)", unnamedNull.name);
63+
64+
Expect.equals("general(non-null)", unnamed.generalName);
65+
Expect.equals("general(null)", unnamedNull.generalName);
66+
67+
Expect.equals("general generic(non-null)", unnamed.generalGenericName);
68+
Expect.equals("general generic(null)", unnamedNull.generalGenericName);
69+
Expect.type<List<Unnamed>>(unnamed.generalList);
70+
Expect.type<List<Unnamed>>(unnamedNull.generalList);
71+
72+
// Named.
73+
Named named = Named();
74+
Named namedNull = null;
75+
76+
Expect.equals("named(non-null)", named.name);
77+
Expect.equals("named(null)", namedNull.name);
78+
79+
Expect.equals("general(non-null)", named.generalName);
80+
Expect.equals("general(null)", namedNull.generalName);
81+
82+
Expect.equals("general generic(non-null)", named.generalGenericName);
83+
Expect.equals("general generic(null)", namedNull.generalGenericName);
84+
Expect.type<List<Named>>(named.generalList);
85+
Expect.type<List<Named>>(namedNull.generalNullList);
86+
87+
// Unnamed Generic.
88+
UnnamedGeneric<num> unnamedGeneric = UnnamedGeneric<int>();
89+
UnnamedGeneric<num> unnamedGenericNull = null;
90+
91+
Expect.equals("unnamed generic(non-null)", unnamedGeneric.name);
92+
Expect.equals("unnamed generic(null)", unnamedGeneric.name);
93+
Expect.type<List<num>>(unnamedGeneric.list);
94+
Expect.notType<List<int>>(unnamedGeneric.list);
95+
Expect.type<List<num>>(unnamedGenericNull.nullList);
96+
Expect.notType<List<int>>(unnamedGenericNull.nullList);
97+
98+
Expect.equals("general(non-null)", unnamedGeneric.generalName);
99+
Expect.equals("general(null)", unnamedGenericNull.generalName);
100+
101+
Expect.equals("general generic(non-null)", unnamedGeneric.generalGenericName);
102+
Expect.equals("general generic(null)", unnamedGenericNull.generalGenericName);
103+
Expect.type<List<UnnamedGeneric<num>>>(unnamedGeneric.generalList);
104+
Expect.type<List<UnnamedGeneric<num>>>(unnamedGenericNull.generalList);
105+
106+
// Named Generic.
107+
NamedGeneric<num> namedGeneric = NamedGeneric<int>();
108+
NamedGeneric<num> namedGenericNull = null;
109+
110+
Expect.equals("named generic(non-null)", namedGeneric.name);
111+
Expect.equals("named generic(null)", namedGenericNull.name);
112+
Expect.type<List<num>>(namedGeneric.list);
113+
Expect.notType<List<int>>(namedGeneric.list);
114+
Expect.type<List<num>>(namedGenericNull.nullList);
115+
Expect.notType<List<int>>(namedGenericNull.nullList);
116+
117+
Expect.equals("general(non-null)", namedGeneric.generalName);
118+
Expect.equals("general(null)", namedGenericNull.generalName);
119+
120+
Expect.equals("general generic(non-null)", namedGeneric.generalGenericName);
121+
Expect.equals("general generic(null)", namedGenericNull.generalGenericName);
122+
Expect.type<List<NamedGeneric<num>>>(namedGeneric.generalList);
123+
Expect.type<List<NamedGeneric<num>>>(namedGenericNull.generalList);
124+
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// SharedOptions=--enable-experiment=extension-methods
6+
7+
// Tests interactions between getters and setters where one or both is defined
8+
// by an extension.
9+
10+
import "package:expect/expect.dart";
11+
12+
main() {
13+
C c = C();
14+
// v1: C get, C set
15+
expectGet("C.v1", c.v1);
16+
expectSet("C.v1=1", c.v1 = Result("1"));
17+
// v2: C get, E1 set
18+
expectGet("C.v2", c.v2);
19+
expectSet("E1.v2=2", c.v2 = Result("2"));
20+
// v3: E1 get, C set
21+
expectGet("E1.v3", c.v3);
22+
expectSet("C.v3=3", c.v3 = Result("3"));
23+
// v4: E1 get, E1 set
24+
expectGet("E1.v4", c.v4);
25+
expectSet("E1.v4=4", c.v4 = Result("4"));
26+
// v5: E1 get, E2 set
27+
expectGet("E1.v5", c.v5);
28+
expectSet("E2.v5=5", c.v5 = Result("5"));
29+
30+
expectSet("C.v1=C.v1+1", c.v1++);
31+
expectSet("E1.v2=C.v2+1", c.v2++);
32+
expectSet("C.v3=E1.v3+1", c.v3++);
33+
expectSet("E1.v4=E1.v4+1", c.v4++);
34+
expectSet("E2.v5=E1.v5+1", c.v5++);
35+
36+
expectSet("C.v1=C.v1+a", c.v1 += "a");
37+
expectSet("C.v1=C.v1-b", c.v1 -= "b");
38+
39+
// Cascades work.
40+
expectSet(
41+
"E1.v4=E2.v4+[C.v1=[E1.v2=a]]",
42+
c
43+
..v2 = Result("a")
44+
..v1 = Result("[$lastSetter]")
45+
..v4 += Result("[$lastSetter]"));
46+
47+
// Override used by all accesses of read/write operations
48+
expectSet("E1.v1=E1.v1+1", E1(c).v1++);
49+
expectSet("E1.v2=E1.v2+1", E1(c).v2++);
50+
expectSet("E1.v3=E1.v3+1", E1(c).v3++);
51+
// Same using `+= 1` instead of `++`.
52+
expectSet("E1.v1=E1.v1+1", E1(c).v1 += 1);
53+
expectSet("E1.v2=E1.v2+1", E1(c).v2 += 1);
54+
expectSet("E1.v3=E1.v3+1", E1(c).v3 += 1);
55+
// Same fully expanded.
56+
expectSet("E1.v1=E1.v1+1", E1(c).v1 = E1(c).v1 + 1);
57+
expectSet("E1.v2=E1.v2+1", E1(c).v2 = E1(c).v2 + 1);
58+
expectSet("E1.v3=E1.v3+1", E1(c).v3 = E1(c).v3 + 1);
59+
}
60+
61+
/// Expect the value of [result] to be the [expected] string
62+
expectGet(String expected, Result result) {
63+
Expect.equals(expected, result.value);
64+
}
65+
66+
/// Expect the [lastSetter] value set by evaluating [assignment] to be
67+
/// [expected].
68+
expectSet(String expected, void assignment) {
69+
Expect.equals(expected, lastSetter);
70+
}
71+
72+
/// Last value passed to any of our tested setters.
73+
String lastSetter = null;
74+
75+
/// A type which supports a `+` operation accepting `int`,
76+
/// so we can test `+=` and `++`.
77+
class Result {
78+
final String value;
79+
Result(this.value);
80+
Result operator +(Object o) => Result("$value+$o");
81+
Result operator -(Object o) => Result("$value-$o");
82+
String toString() => value;
83+
}
84+
85+
/// Target type for extensions.
86+
///
87+
/// Declares [v1] getter and setter, [v2] getter and [v3] setter.
88+
class C {
89+
Result get v1 => Result("C.v1");
90+
void set v1(Result value) {
91+
lastSetter = "C.v1=$value";
92+
}
93+
94+
Result get v2 => Result("C.v2");
95+
96+
void set v3(Result value) {
97+
lastSetter = "C.v3=$value";
98+
}
99+
}
100+
101+
/// Primary extension on [C].
102+
///
103+
/// Declares [v1], [v2] and [v3] getters and setters.
104+
///
105+
/// Declares [v4] getter and setter, and [v5] getter
106+
/// which are supplemented by a setter from the [E2] extension.
107+
extension E1 on C {
108+
// Overlaps with C on both.
109+
Result get v1 => Result("E1.v1");
110+
111+
void set v1(Result value) {
112+
lastSetter = "E1.v1=$value";
113+
}
114+
115+
// Overlaps with C on getter.
116+
Result get v2 => Result("E1.v2");
117+
118+
void set v2(Result value) {
119+
lastSetter = "E1.v2=$value";
120+
}
121+
122+
// Overlaps with C on setter.
123+
Result get v3 => Result("E1.v3");
124+
125+
void set v3(Result value) {
126+
lastSetter = "E1.v3=$value";
127+
}
128+
129+
// Overlaps with nothing.
130+
Result get v4 => Result("E1.v4");
131+
void set v4(Result value) {
132+
lastSetter = "E1.v4=$value";
133+
}
134+
135+
// Combines with E2 setter.
136+
Result get v5 => Result("E1.v5");
137+
}
138+
139+
/// A different extension than [E1] on [C].
140+
///
141+
/// Declares [v5] setter.
142+
/// Together with [E1], this defined both getter and setter.
143+
extension E2 on C {
144+
void set v5(Result value) {
145+
lastSetter = "E2.v5=$value";
146+
}
147+
}

0 commit comments

Comments
 (0)