1 /*******************************************************************************
2  * Copyright (c) Mar 12, 2016 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jdt.debug.tests.variables;
15 
16 import org.eclipse.debug.core.model.IValue;
17 import org.eclipse.debug.ui.IValueDetailListener;
18 import org.eclipse.jdt.core.IJavaProject;
19 import org.eclipse.jdt.core.Signature;
20 import org.eclipse.jdt.debug.core.IJavaThread;
21 import org.eclipse.jdt.debug.core.IJavaValue;
22 import org.eclipse.jdt.debug.core.IJavaVariable;
23 import org.eclipse.jdt.debug.tests.AbstractDebugTest;
24 import org.eclipse.jdt.internal.debug.ui.DetailFormatter;
25 import org.eclipse.jdt.internal.debug.ui.JavaDetailFormattersManager;
26 
27 /**
28  * Tests detail formatters
29  *
30  * @since 3.8.100
31  */
32 public class DetailFormatterTests extends AbstractDebugTest {
33 
34 	class TestListener implements IValueDetailListener {
35 		IValue value;
36 		String result;
37 
38 		@Override
detailComputed(IValue value, String result)39 		public void detailComputed(IValue value, String result) {
40 			this.value = value;
41 			this.result = result;
42 		}
43 
reset()44 		void reset() {
45 			value = null;
46 			result = null;
47 		}
48 	}
49 
50 	TestListener fListener = new TestListener();
51 
52 	/**
53 	 * @param name
54 	 */
DetailFormatterTests(String name)55 	public DetailFormatterTests(String name) {
56 		super(name);
57 	}
58 
59 	@Override
getProjectContext()60 	protected IJavaProject getProjectContext() {
61 		return get15Project();
62 	}
63 
64 	@Override
tearDown()65 	protected void tearDown() throws Exception {
66 		fListener.reset();
67 		super.tearDown();
68 	}
69 
70 	/**
71 	 * Tests a detail formatter made from a large compound expression
72 	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=403028
73 	 * @throws Exception
74 	 */
testCompoundDetails1()75 	public void testCompoundDetails1() throws Exception {
76 		IJavaThread thread = null;
77 		DetailFormatter formatter = null;
78 		JavaDetailFormattersManager jdfm = JavaDetailFormattersManager.getDefault();
79 		try {
80 			String typename = "a.b.c.bug403028";
81 			createLineBreakpoint(10, typename);
82 			thread = launchToBreakpoint(typename);
83 			assertNotNull("The program did not suspend", thread);
84 			String snippet = "StringBuilder buf = new StringBuilder();\n"
85 					+ "buf.append(\"{\");\n"
86 					+ "Iterator i = this.entrySet().iterator();\n"
87 					+ "boolean hasNext = i.hasNext();\n"
88 					+ "while (hasNext) {\n"
89 					+ "    Entry e = (Entry) (i.next());\n"
90 					+ "    Object key = e.getKey();\n"
91 					+ "    Object value = e.getValue();\n"
92 					+ "    buf.append((key == this ?  \"(this Map)\" : key) + \"=\" + \n"
93 					+ "            (value == this ? \"(this Map)\": value));\n"
94 					+ "    hasNext = i.hasNext();\n"
95 					+ "    if (hasNext)\n"
96 					+ "        buf.append(\"\n,\");\n"
97 					+ "}\n"
98 					+ "buf.append(\"}\");\n"
99 					+ "return buf.toString();";
100 			formatter = new DetailFormatter("java.util.HashMap", snippet, true);
101 			jdfm.setAssociatedDetailFormatter(formatter);
102 			IJavaVariable var = thread.findVariable("map");
103 			assertNotNull("the variable 'map' must exist in the frame", var);
104 			jdfm.computeValueDetail((IJavaValue) var.getValue(), thread, fListener);
105 			long timeout = System.currentTimeMillis()+5000;
106 			while(fListener.value == null && System.currentTimeMillis() < timeout) {
107 				Thread.sleep(100);
108 			}
109 			assertNotNull("The IValue of the detailComputed callback cannot be null", fListener.value);
110 			assertTrue("The map should be an instance of java.util.LinkedHashMap",
111 					Signature.getTypeErasure(fListener.value.getReferenceTypeName()).equals("java.util.LinkedHashMap"));
112 			assertNotNull("The computed value of the detail should not be null", fListener.result);
113 		}
114 		finally {
115 			jdfm.removeAssociatedDetailFormatter(formatter);
116 			terminateAndRemove(thread);
117 			removeAllBreakpoints();
118 		}
119 	}
120 
121 	/**
122 	 * Tests a detail formatter made from a small compound expression
123 	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=403028
124 	 * @throws Exception
125 	 */
testCompoundDetails2()126 	public void testCompoundDetails2() throws Exception {
127 		IJavaThread thread = null;
128 		DetailFormatter formatter = null;
129 		JavaDetailFormattersManager jdfm = JavaDetailFormattersManager.getDefault();
130 		try {
131 			String typename = "a.b.c.bug403028";
132 			createLineBreakpoint(10, typename);
133 			thread = launchToBreakpoint(typename);
134 			assertNotNull("The program did not suspend", thread);
135 			String snippet = "StringBuilder buf = new StringBuilder();\n"
136 					+ "buf.append(this);\n"
137 					+ "return buf.toString();";
138 			formatter = new DetailFormatter("java.util.HashMap", snippet, true);
139 			jdfm.setAssociatedDetailFormatter(formatter);
140 			IJavaVariable var = thread.findVariable("map");
141 			assertNotNull("the variable 'map' must exist in the frame", var);
142 			jdfm.computeValueDetail((IJavaValue) var.getValue(), thread, fListener);
143 			long timeout = System.currentTimeMillis()+5000;
144 			while(fListener.value == null && System.currentTimeMillis() < timeout) {
145 				Thread.sleep(100);
146 			}
147 			assertNotNull("The IValue of the detailComputed callback cannot be null", fListener.value);
148 			assertTrue("The map should be an instance of java.util.LinkedHashMap",
149 					Signature.getTypeErasure(fListener.value.getReferenceTypeName()).equals("java.util.LinkedHashMap"));
150 			assertNotNull("The computed value of the detail should not be null", fListener.result);
151 		}
152 		finally {
153 			jdfm.removeAssociatedDetailFormatter(formatter);
154 			terminateAndRemove(thread);
155 			removeAllBreakpoints();
156 		}
157 	}
158 
159 	/**
160 	 * Tests a detail formatter made from a small compound expression
161 	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=403028
162 	 * @throws Exception
163 	 */
testSimpleDetails1()164 	public void testSimpleDetails1() throws Exception {
165 		IJavaThread thread = null;
166 		DetailFormatter formatter = null;
167 		JavaDetailFormattersManager jdfm = JavaDetailFormattersManager.getDefault();
168 		try {
169 			String typename = "a.b.c.bug403028";
170 			createLineBreakpoint(10, typename);
171 			thread = launchToBreakpoint(typename);
172 			assertNotNull("The program did not suspend", thread);
173 			String snippet = "return toString();";
174 			formatter = new DetailFormatter("java.util.HashMap", snippet, true);
175 			jdfm.setAssociatedDetailFormatter(formatter);
176 			IJavaVariable var = thread.findVariable("map");
177 			assertNotNull("the variable 'map' must exist in the frame", var);
178 			jdfm.computeValueDetail((IJavaValue) var.getValue(), thread, fListener);
179 			long timeout = System.currentTimeMillis()+5000;
180 			while(fListener.value == null && System.currentTimeMillis() < timeout) {
181 				Thread.sleep(100);
182 			}
183 			assertNotNull("The IValue of the detailComputed callback cannot be null", fListener.value);
184 			assertTrue("The map should be an instance of java.util.LinkedHashMap",
185 					Signature.getTypeErasure(fListener.value.getReferenceTypeName()).equals("java.util.LinkedHashMap"));
186 			assertNotNull("The computed value of the detail should not be null", fListener.result);
187 		}
188 		finally {
189 			jdfm.removeAssociatedDetailFormatter(formatter);
190 			terminateAndRemove(thread);
191 			removeAllBreakpoints();
192 		}
193 	}
194 
195 	/**
196 	 * Tests a detail formatter made from a small compound expression
197 	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=403028
198 	 * @throws Exception
199 	 */
testSimpleDetails2()200 	public void testSimpleDetails2() throws Exception {
201 		IJavaThread thread = null;
202 		DetailFormatter formatter = null;
203 		JavaDetailFormattersManager jdfm = JavaDetailFormattersManager.getDefault();
204 		try {
205 			String typename = "a.b.c.bug403028";
206 			createLineBreakpoint(10, typename);
207 			thread = launchToBreakpoint(typename);
208 			assertNotNull("The program did not suspend", thread);
209 			String snippet = "return \"map test detail formatter [\" + toString() + \"]\";";
210 			formatter = new DetailFormatter("java.util.HashMap", snippet, true);
211 			jdfm.setAssociatedDetailFormatter(formatter);
212 			IJavaVariable var = thread.findVariable("map");
213 			assertNotNull("the variable 'map' must exist in the frame", var);
214 			jdfm.computeValueDetail((IJavaValue) var.getValue(), thread, fListener);
215 			long timeout = System.currentTimeMillis()+5000;
216 			while(fListener.value == null && System.currentTimeMillis() < timeout) {
217 				Thread.sleep(100);
218 			}
219 			assertNotNull("The IValue of the detailComputed callback cannot be null", fListener.value);
220 			assertTrue("The map should be an instance of java.util.LinkedHashMap",
221 					Signature.getTypeErasure(fListener.value.getReferenceTypeName()).equals("java.util.LinkedHashMap"));
222 			assertNotNull("The computed value of the detail should not be null", fListener.result);
223 		}
224 		finally {
225 			jdfm.removeAssociatedDetailFormatter(formatter);
226 			terminateAndRemove(thread);
227 			removeAllBreakpoints();
228 		}
229 	}
230 
231 	/**
232 	 * Tests a detail formatter made from an infix expression
233 	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=403028
234 	 * @throws Exception
235 	 */
testInfixDetails1()236 	public void testInfixDetails1() throws Exception {
237 		IJavaThread thread = null;
238 		DetailFormatter formatter = null;
239 		JavaDetailFormattersManager jdfm = JavaDetailFormattersManager.getDefault();
240 		try {
241 			String typename = "a.b.c.bug403028";
242 			createLineBreakpoint(10, typename);
243 			thread = launchToBreakpoint(typename);
244 			assertNotNull("The program did not suspend", thread);
245 			String snippet = "return (true && true || !(false&&true) || !(true==true||true!=true&&true));";
246 			formatter = new DetailFormatter("java.util.HashMap", snippet, true);
247 			jdfm.setAssociatedDetailFormatter(formatter);
248 			IJavaVariable var = thread.findVariable("map");
249 			assertNotNull("the variable 'map' must exist in the frame", var);
250 			jdfm.computeValueDetail((IJavaValue) var.getValue(), thread, fListener);
251 			long timeout = System.currentTimeMillis()+5000;
252 			while(fListener.value == null && System.currentTimeMillis() < timeout) {
253 				Thread.sleep(100);
254 			}
255 			assertNotNull("The IValue of the detailComputed callback cannot be null", fListener.value);
256 			assertTrue("The map should be an instance of java.util.LinkedHashMap",
257 					Signature.getTypeErasure(fListener.value.getReferenceTypeName()).equals("java.util.LinkedHashMap"));
258 			assertNotNull("The computed value of the detail should not be null", fListener.result);
259 			assertTrue("The returned value from (true && true || !(false&&true) || !(true==true||true!=true&&true)) should be true",
260 					Boolean.parseBoolean(fListener.result));
261 		}
262 		finally {
263 			jdfm.removeAssociatedDetailFormatter(formatter);
264 			terminateAndRemove(thread);
265 			removeAllBreakpoints();
266 		}
267 	}
268 
269 	/**
270 	 * Tests a detail formatter made from an infix expression
271 	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=403028
272 	 * @throws Exception
273 	 */
testInfixDetails2()274 	public void testInfixDetails2() throws Exception {
275 		IJavaThread thread = null;
276 		DetailFormatter formatter = null;
277 		JavaDetailFormattersManager jdfm = JavaDetailFormattersManager.getDefault();
278 		try {
279 			String typename = "a.b.c.bug403028";
280 			createLineBreakpoint(10, typename);
281 			thread = launchToBreakpoint(typename);
282 			assertNotNull("The program did not suspend", thread);
283 			String snippet = "return !true;";
284 			formatter = new DetailFormatter("java.util.HashMap", snippet, true);
285 			jdfm.setAssociatedDetailFormatter(formatter);
286 			IJavaVariable var = thread.findVariable("map");
287 			assertNotNull("the variable 'map' must exist in the frame", var);
288 			jdfm.computeValueDetail((IJavaValue) var.getValue(), thread, fListener);
289 			long timeout = System.currentTimeMillis()+5000;
290 			while(fListener.value == null && System.currentTimeMillis() < timeout) {
291 				Thread.sleep(100);
292 			}
293 			assertNotNull("The IValue of the detailComputed callback cannot be null", fListener.value);
294 			assertTrue("The map should be an instance of java.util.LinkedHashMap",
295 					Signature.getTypeErasure(fListener.value.getReferenceTypeName()).equals("java.util.LinkedHashMap"));
296 			assertNotNull("The computed value of the detail should not be null", fListener.result);
297 			assertFalse("The returned value from !true should be false", Boolean.parseBoolean(fListener.result));
298 		}
299 		finally {
300 			jdfm.removeAssociatedDetailFormatter(formatter);
301 			terminateAndRemove(thread);
302 			removeAllBreakpoints();
303 		}
304 	}
305 
306 	/**
307 	 * Tests a detail formatter made from an infix expression
308 	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=403028
309 	 * @throws Exception
310 	 */
testInfixDetails3()311 	public void testInfixDetails3() throws Exception {
312 		IJavaThread thread = null;
313 		DetailFormatter formatter = null;
314 		JavaDetailFormattersManager jdfm = JavaDetailFormattersManager.getDefault();
315 		try {
316 			String typename = "a.b.c.bug403028";
317 			createLineBreakpoint(10, typename);
318 			thread = launchToBreakpoint(typename);
319 			assertNotNull("The program did not suspend", thread);
320 			String snippet = "return !(true==true||true!=true&&true);";
321 			formatter = new DetailFormatter("java.util.HashMap", snippet, true);
322 			jdfm.setAssociatedDetailFormatter(formatter);
323 			IJavaVariable var = thread.findVariable("map");
324 			assertNotNull("the variable 'map' must exist in the frame", var);
325 			jdfm.computeValueDetail((IJavaValue) var.getValue(), thread, fListener);
326 			long timeout = System.currentTimeMillis()+5000;
327 			while(fListener.value == null && System.currentTimeMillis() < timeout) {
328 				Thread.sleep(100);
329 			}
330 			assertNotNull("The IValue of the detailComputed callback cannot be null", fListener.value);
331 			assertTrue("The map should be an instance of java.util.LinkedHashMap",
332 					Signature.getTypeErasure(fListener.value.getReferenceTypeName()).equals("java.util.LinkedHashMap"));
333 			assertNotNull("The computed value of the detail should not be null", fListener.result);
334 			assertFalse("The returned value from !(true==true||true!=true&&true) should be false", Boolean.parseBoolean(fListener.result));
335 		}
336 		finally {
337 			jdfm.removeAssociatedDetailFormatter(formatter);
338 			terminateAndRemove(thread);
339 			removeAllBreakpoints();
340 		}
341 	}
342 
343 	/**
344 	 * Tests a detail formatter made from an collection with no type arguments
345 	 *
346 	 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=484686
347 	 * @throws Exception
348 	 */
testHoverWithNoTypeArguments()349 	public void testHoverWithNoTypeArguments() throws Exception {
350 		IJavaThread thread = null;
351 		DetailFormatter formatter = null;
352 		JavaDetailFormattersManager jdfm = JavaDetailFormattersManager.getDefault();
353 		try {
354 			String typename = "a.b.c.bug484686";
355 			createLineBreakpoint(8, typename);
356 			thread = launchToBreakpoint(typename);
357 			assertNotNull("The program did not suspend", thread);
358 			String snippet = "StringBuilder sb = new StringBuilder();\n" + "for (Object obj : this) { \n" + "sb.append(obj).append(\"\\n\"); }\n"
359 					+ "return sb.toString();";
360 			formatter = new DetailFormatter("java.util.Collection", snippet, true);
361 			jdfm.setAssociatedDetailFormatter(formatter);
362 			IJavaVariable var = thread.findVariable("coll");
363 			assertNotNull("the variable 'coll' must exist in the frame", var);
364 			jdfm.computeValueDetail((IJavaValue) var.getValue(), thread, fListener);
365 			long timeout = System.currentTimeMillis() + 5000;
366 			while (fListener.value == null && System.currentTimeMillis() < timeout) {
367 				Thread.sleep(100);
368 			}
369 			assertNotNull("The IValue of the detailComputed callback cannot be null", fListener.value);
370 			assertNotNull("The computed value of the detail should not be null", fListener.result);
371 		}
372 		finally {
373 			jdfm.removeAssociatedDetailFormatter(formatter);
374 			terminateAndRemove(thread);
375 			removeAllBreakpoints();
376 		}
377 	}
378 }
379