|
1 /* |
|
2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 */ |
|
23 |
|
24 /* |
|
25 * @test 8080069 8152925 |
|
26 * @summary Test of Snippet redefinition and replacement. |
|
27 * @build KullaTesting TestingInputStream |
|
28 * @run testng ReplaceTest |
|
29 */ |
|
30 |
|
31 import java.util.Iterator; |
|
32 import java.util.stream.Stream; |
|
33 import jdk.jshell.Snippet; |
|
34 import jdk.jshell.MethodSnippet; |
|
35 import jdk.jshell.TypeDeclSnippet; |
|
36 import jdk.jshell.VarSnippet; |
|
37 import org.testng.annotations.Test; |
|
38 |
|
39 import static org.testng.Assert.assertFalse; |
|
40 import static jdk.jshell.Snippet.Status.*; |
|
41 import static jdk.jshell.Snippet.SubKind.*; |
|
42 import static org.testng.Assert.assertTrue; |
|
43 |
|
44 @Test |
|
45 public class ReplaceTest extends KullaTesting { |
|
46 |
|
47 public void testRedefine() { |
|
48 Snippet vx = varKey(assertEval("int x;")); |
|
49 Snippet mu = methodKey(assertEval("int mu() { return x * 4; }")); |
|
50 Snippet c = classKey(assertEval("class C { String v() { return \"#\" + mu(); } }")); |
|
51 assertEval("C c0 = new C();"); |
|
52 assertEval("c0.v();", "\"#0\""); |
|
53 assertEval("int x = 10;", "10", |
|
54 ste(MAIN_SNIPPET, VALID, VALID, false, null), |
|
55 ste(vx, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
56 assertEval("c0.v();", "\"#40\""); |
|
57 assertEval("C c = new C();"); |
|
58 assertEval("c.v();", "\"#40\""); |
|
59 assertEval("int mu() { return x * 3; }", |
|
60 ste(MAIN_SNIPPET, VALID, VALID, false, null), |
|
61 ste(mu, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
62 assertEval("c.v();", "\"#30\""); |
|
63 assertEval("class C { String v() { return \"@\" + mu(); } }", |
|
64 ste(MAIN_SNIPPET, VALID, VALID, false, null), |
|
65 ste(c, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
66 assertEval("c0.v();", "\"@30\""); |
|
67 assertEval("c = new C();"); |
|
68 assertEval("c.v();", "\"@30\""); |
|
69 assertActiveKeys(); |
|
70 } |
|
71 |
|
72 public void testReplaceClassToVar() { |
|
73 Snippet oldA = classKey(assertEval("class A { public String toString() { return \"old\"; } }")); |
|
74 Snippet v = varKey(assertEval("A a = new A();", "old")); |
|
75 assertEval("a;", "old"); |
|
76 Snippet midA = classKey(assertEval("class A { public String toString() { return \"middle\"; } }", |
|
77 ste(MAIN_SNIPPET, VALID, VALID, false, null), |
|
78 ste(oldA, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); |
|
79 assertEval("a;", "middle"); |
|
80 assertEval("class A { int x; public String toString() { return \"new\"; } }", |
|
81 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
82 ste(midA, VALID, OVERWRITTEN, false, MAIN_SNIPPET), |
|
83 ste(v, VALID, VALID, true, MAIN_SNIPPET)); |
|
84 assertEval("a;", "null"); |
|
85 assertActiveKeys(); |
|
86 } |
|
87 |
|
88 private <T extends Snippet> void identityMatch(Stream<T> got, T expected) { |
|
89 Iterator<T> it = got.iterator(); |
|
90 assertTrue(it.hasNext(), "expected exactly one"); |
|
91 assertTrue(expected == it.next(), "Identity must not change"); |
|
92 assertFalse(it.hasNext(), "expected exactly one"); |
|
93 } |
|
94 |
|
95 public void testReplaceVarToMethod() { |
|
96 Snippet x = varKey(assertEval("int x;")); |
|
97 MethodSnippet musn = methodKey(assertEval("double mu() { return x * 4; }")); |
|
98 assertEval("x == 0;", "true"); |
|
99 assertEval("mu() == 0.0;", "true"); |
|
100 assertEval("double x = 2.5;", |
|
101 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
102 ste(x, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
103 identityMatch(getState().methods(), musn); |
|
104 assertEval("x == 2.5;", "true"); |
|
105 assertEval("mu() == 10.0;", "true"); // Auto redefine |
|
106 assertActiveKeys(); |
|
107 } |
|
108 |
|
109 public void testReplaceMethodToMethod() { |
|
110 Snippet a = methodKey(assertEval("double a() { return 2; }")); |
|
111 Snippet b = methodKey(assertEval("double b() { return a() * 10; }")); |
|
112 assertEval("double c() { return b() * 3; }"); |
|
113 assertEval("double d() { return c() + 1000; }"); |
|
114 assertEval("d();", "1060.0"); |
|
115 assertEval("int a() { return 5; }", |
|
116 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
117 ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
118 assertEval("d();", "1150.0"); |
|
119 assertActiveKeys(); |
|
120 } |
|
121 |
|
122 public void testReplaceClassToMethod() { |
|
123 Snippet c = classKey(assertEval("class C { int f() { return 7; } }")); |
|
124 Snippet m = methodKey(assertEval("int m() { return new C().f(); }")); |
|
125 assertEval("m();", "7"); |
|
126 assertEval("class C { int x = 99; int f() { return x; } }", |
|
127 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
128 ste(c, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
129 assertEval("m();", "99"); |
|
130 assertActiveKeys(); |
|
131 } |
|
132 |
|
133 public void testReplaceVarToClass() { |
|
134 Snippet x = varKey(assertEval("int x;")); |
|
135 TypeDeclSnippet c = classKey(assertEval("class A { double a = 4 * x; }")); |
|
136 assertEval("x == 0;", "true"); |
|
137 assertEval("new A().a == 0.0;", "true"); |
|
138 assertEval("double x = 2.5;", |
|
139 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
140 ste(x, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
141 identityMatch(getState().types(), c); |
|
142 assertEval("x == 2.5;", "true"); |
|
143 assertEval("new A().a == 10.0;", "true"); |
|
144 assertActiveKeys(); |
|
145 } |
|
146 |
|
147 public void testReplaceMethodToClass() { |
|
148 Snippet x = methodKey(assertEval("int x() { return 0; }")); |
|
149 TypeDeclSnippet c = classKey(assertEval("class A { double a = 4 * x(); }")); |
|
150 assertEval("x() == 0;", "true"); |
|
151 assertEval("new A().a == 0.0;", "true"); |
|
152 assertEval("double x() { return 2.5; }", |
|
153 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
154 ste(x, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
155 assertEval("x();", "2.5"); |
|
156 identityMatch(getState().types(), c); |
|
157 assertEval("x() == 2.5;", "true"); |
|
158 assertEval("new A().a == 10.0;", "true"); |
|
159 assertActiveKeys(); |
|
160 } |
|
161 |
|
162 public void testReplaceClassToClass() { |
|
163 TypeDeclSnippet a = classKey(assertEval("class A {}")); |
|
164 assertTypeDeclSnippet(a, "A", VALID, CLASS_SUBKIND, 0, 0); |
|
165 TypeDeclSnippet b = classKey(assertEval("class B extends A {}")); |
|
166 TypeDeclSnippet c = classKey(assertEval("class C extends B {}")); |
|
167 TypeDeclSnippet d = classKey(assertEval("class D extends C {}")); |
|
168 assertEval("class A { int x; public String toString() { return \"NEW\"; } }", |
|
169 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
170 ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET), |
|
171 ste(b, VALID, VALID, true, MAIN_SNIPPET), |
|
172 ste(c, VALID, VALID, true, b), |
|
173 ste(d, VALID, VALID, true, c)); |
|
174 assertTypeDeclSnippet(b, "B", VALID, CLASS_SUBKIND, 0, 0); |
|
175 assertTypeDeclSnippet(c, "C", VALID, CLASS_SUBKIND, 0, 0); |
|
176 assertTypeDeclSnippet(d, "D", VALID, CLASS_SUBKIND, 0, 0); |
|
177 assertEval("new D();", "NEW"); |
|
178 assertActiveKeys(); |
|
179 } |
|
180 |
|
181 public void testOverwriteReplaceMethod() { |
|
182 MethodSnippet k1 = methodKey(assertEval("String m(Integer i) { return i.toString(); }")); |
|
183 MethodSnippet k2 = methodKey(assertEval("String m(java.lang.Integer i) { return \"java.lang.\" + i.toString(); }", |
|
184 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
185 ste(k1, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); |
|
186 assertMethodDeclSnippet(k1, "m", "(Integer)String", OVERWRITTEN, 0, 0); |
|
187 assertEval("m(6);", "\"java.lang.6\""); |
|
188 assertEval("String m(Integer i) { return i.toString(); }", |
|
189 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
190 ste(k2, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
191 assertMethodDeclSnippet(k2, "m", "(java.lang.Integer)String", OVERWRITTEN, 0, 0); |
|
192 assertEval("m(6);", "\"6\""); |
|
193 assertActiveKeys(); |
|
194 } |
|
195 |
|
196 public void testImportDeclare() { |
|
197 Snippet singleImport = importKey(assertEval("import java.util.List;", added(VALID))); |
|
198 Snippet importOnDemand = importKey(assertEval("import java.util.*;", added(VALID))); |
|
199 Snippet singleStaticImport = importKey(assertEval("import static java.lang.Math.abs;", added(VALID))); |
|
200 Snippet staticImportOnDemand = importKey(assertEval("import static java.lang.Math.*;", added(VALID))); |
|
201 assertEval("import java.util.List; //again", |
|
202 ste(MAIN_SNIPPET, VALID, VALID, false, null), |
|
203 ste(singleImport, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
204 assertEval("import java.util.*; //again", |
|
205 ste(MAIN_SNIPPET, VALID, VALID, false, null), |
|
206 ste(importOnDemand, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
207 assertEval("import static java.lang.Math.abs; //again", |
|
208 ste(MAIN_SNIPPET, VALID, VALID, false, null), |
|
209 ste(singleStaticImport, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
210 assertEval("import static java.lang.Math.*; //again", |
|
211 ste(MAIN_SNIPPET, VALID, VALID, false, null), |
|
212 ste(staticImportOnDemand, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); |
|
213 assertActiveKeys(); |
|
214 } |
|
215 |
|
216 @Test(enabled = false) // TODO 8129420 |
|
217 public void testLocalClassEvolve() { |
|
218 Snippet j = methodKey(assertEval("Object j() { return null; }", added(VALID))); |
|
219 assertEval("Object j() { class B {}; return null; }", |
|
220 ste(MAIN_SNIPPET, VALID, VALID, false, null)); |
|
221 assertEval("Object j() { class B {}; return new B(); }", |
|
222 ste(MAIN_SNIPPET, VALID, VALID, false, null)); |
|
223 assertEval("j().getClass().getSimpleName();", "\"B\""); |
|
224 assertEval("Object j() { class B { int p; public String toString() { return \"Yep\";} }; return new B(); }", |
|
225 ste(MAIN_SNIPPET, VALID, VALID, false, null)); |
|
226 assertEval("j().getClass().getSimpleName();", "\"B\""); |
|
227 assertEval("j();", "Yep"); |
|
228 } |
|
229 |
|
230 public void testReplaceCausesMethodReferenceError() { |
|
231 Snippet l = classKey(assertEval("interface Logger { public void log(String message); }", added(VALID))); |
|
232 Snippet v = varKey(assertEval("Logger l = System.out::println;", added(VALID))); |
|
233 assertEval("interface Logger { public boolean accept(String message); }", |
|
234 DiagCheck.DIAG_OK, |
|
235 DiagCheck.DIAG_ERROR, |
|
236 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
237 ste(l, VALID, OVERWRITTEN, false, MAIN_SNIPPET), |
|
238 ste(v, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET)); |
|
239 } |
|
240 |
|
241 public void testReplaceCausesClassCompilationError() { |
|
242 Snippet l = classKey(assertEval("interface L { }", added(VALID))); |
|
243 Snippet c = classKey(assertEval("class C implements L { }", added(VALID))); |
|
244 assertEval("interface L { void m(); }", |
|
245 DiagCheck.DIAG_OK, |
|
246 DiagCheck.DIAG_ERROR, |
|
247 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
248 ste(l, VALID, OVERWRITTEN, false, MAIN_SNIPPET), |
|
249 ste(c, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET)); |
|
250 } |
|
251 |
|
252 public void testOverwriteNoUpdate() { |
|
253 String xsi = "int x = 5;"; |
|
254 String xsd = "double x = 3.14159;"; |
|
255 VarSnippet xi = varKey(assertEval(xsi, added(VALID))); |
|
256 String ms1 = "double m(Integer i) { return i + x; }"; |
|
257 String ms2 = "double m(java.lang.Integer i) { return i + x; }"; |
|
258 MethodSnippet k1 = methodKey(assertEval(ms1, added(VALID))); |
|
259 VarSnippet xd = varKey(assertEval(xsd, |
|
260 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
261 ste(xi, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); |
|
262 MethodSnippet k2 = methodKey(assertEval(ms2, |
|
263 ste(MAIN_SNIPPET, VALID, VALID, true, null), //TODO: technically, should be false |
|
264 ste(k1, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); |
|
265 VarSnippet xi2 = varKey(assertEval(xsi, |
|
266 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
267 ste(xd, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); |
|
268 varKey(assertEval(xsd, |
|
269 ste(MAIN_SNIPPET, VALID, VALID, true, null), |
|
270 ste(xi2, VALID, OVERWRITTEN, false, MAIN_SNIPPET))); |
|
271 } |
|
272 } |