1 /*******************************************************************************
2  * Copyright (c) 2005, 2020 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.text.tests;
15 
16 import static org.junit.Assert.assertEquals;
17 import static org.junit.Assert.assertNull;
18 
19 import java.util.Arrays;
20 import java.util.Comparator;
21 
22 import org.junit.After;
23 import org.junit.Before;
24 import org.junit.Rule;
25 import org.junit.Test;
26 
27 import org.eclipse.jdt.testplugin.JavaProjectHelper;
28 
29 import org.eclipse.jdt.core.ICompilationUnit;
30 import org.eclipse.jdt.core.IJavaProject;
31 import org.eclipse.jdt.core.IPackageFragment;
32 import org.eclipse.jdt.core.IPackageFragmentRoot;
33 import org.eclipse.jdt.core.JavaModelException;
34 import org.eclipse.jdt.core.dom.ASTParser;
35 import org.eclipse.jdt.core.dom.CompilationUnit;
36 
37 import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder.OccurrenceLocation;
38 import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
39 
40 import org.eclipse.jdt.ui.tests.core.rules.ProjectTestSetup;
41 
42 import org.eclipse.jdt.internal.ui.search.BreakContinueTargetFinder;
43 
44 /**
45  * Tests for the BreakContinueTargerFinder class.
46  *
47  * @since 3.2
48  */
49 public class BreakContinueTargetFinderTest {
50 	@Rule
51 	public ProjectTestSetup pts= new ProjectTestSetup();
52 
53 	private ASTParser fParser;
54 	private BreakContinueTargetFinder fFinder;
55 	private IJavaProject fJProject1;
56 	private IPackageFragmentRoot fSourceFolder;
57 
58 	/*
59 	 * @see junit.framework.TestCase#setUp()
60 	 */
61 	@Before
setUp()62 	public void setUp() throws Exception {
63 		fParser = ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
64 		fFinder= new BreakContinueTargetFinder();
65 
66 		fJProject1= ProjectTestSetup.getProject();
67 		fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
68 	}
69 
70 	@After
tearDown()71 	public void tearDown() throws Exception {
72 		JavaProjectHelper.clear(fJProject1, ProjectTestSetup.getDefaultClasspath());
73 	}
74 
getHighlights(StringBuffer source, int offset, int length)75 	private OccurrenceLocation[] getHighlights(StringBuffer source, int offset, int length) throws Exception {
76 		CompilationUnit root = createCompilationUnit(source);
77 		String errorString = fFinder.initialize(root, offset, length);
78 		assertNull(errorString, errorString);
79 		return fFinder.getOccurrences();
80 	}
81 
createCompilationUnit(StringBuffer source)82 	private CompilationUnit createCompilationUnit(StringBuffer source) throws JavaModelException {
83 		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
84 		ICompilationUnit cu= pack1.createCompilationUnit("E.java", source.toString(), false, null);
85 		fParser.setSource(cu);
86 		return (CompilationUnit) fParser.createAST(null);
87 	}
88 
checkSelection(StringBuffer s, int offset, int length, OccurrenceLocation[] expected)89 	private void checkSelection(StringBuffer s, int offset, int length, OccurrenceLocation[] expected) throws Exception {
90 		OccurrenceLocation[] selectedNodes= getHighlights(s, offset, length);
91 		assertEquals("number of selections", expected.length, selectedNodes.length);
92 		sortByStartIndex(selectedNodes);
93 		sortByStartIndex(expected);
94 		for (int i= 0; i < selectedNodes.length; i++) {
95 			assertEquals(expected[i].getOffset(), selectedNodes[i].getOffset());
96 			assertEquals(expected[i].getLength(), selectedNodes[i].getLength());
97 		}
98 	}
99 
sortByStartIndex(OccurrenceLocation[] OccurrenceLocations)100 	private void sortByStartIndex(OccurrenceLocation[] OccurrenceLocations) {
101 		Arrays.sort(OccurrenceLocations, new Comparator<OccurrenceLocation>() {
102 			@Override
103 			public int compare(OccurrenceLocation node0, OccurrenceLocation node1) {
104 				return node0.getOffset() - node1.getOffset();
105 			}
106 		});
107 	}
108 
109 	//pattern must be found - otherwise it's assumed to be an error
find(StringBuffer s, String pattern, int ithOccurrence)110 	private OccurrenceLocation find(StringBuffer s, String pattern, int ithOccurrence) {
111 		if (ithOccurrence < 1)
112 			throw new IllegalStateException("ithOccurrence = " + ithOccurrence);
113 		return find(s, pattern, ithOccurrence, 0);
114 	}
115 
find(StringBuffer s, String pattern, int ithOccurrence, int startIdx)116 	private OccurrenceLocation find(StringBuffer s, String pattern, int ithOccurrence, int startIdx) {
117 		if (startIdx < 0 || startIdx > s.length())
118 			throw new IllegalStateException("startIdx = " + startIdx);
119 		int idx = s.indexOf(pattern, startIdx);
120 		if (idx == -1)
121 			throw new IllegalStateException("not found \"" + pattern + "\" in \"" + s.substring(startIdx));
122 		if (ithOccurrence == 1)
123 			return new OccurrenceLocation(idx, pattern.length(), 0, "");
124 	    return find(s, pattern, ithOccurrence-1, idx+1);
125 	}
126 
127 	@Test
testBreakFor()128 	public void testBreakFor() throws Exception {
129 		StringBuffer s= new StringBuffer();
130 		s.append("class A{\n");
131 		s.append("   void foo(int[] xs){\n");
132 		s.append("      for (int i = 0; i < xs.length; i++) {\n");
133 		s.append("          break;");
134 		s.append("      }\n");
135 		s.append("   }\n");
136 		s.append("}\n");
137 		int offset= 1 + s.indexOf("break");//middle of word
138 		int length= 0;
139 		OccurrenceLocation[] ranges= { find(s, "for", 1), find(s, "}", 1) };
140 		checkSelection(s, offset, length, ranges);
141 	}
142 
143 	@Test
testBreakForeach()144 	public void testBreakForeach() throws Exception {
145 		StringBuffer s= new StringBuffer();
146 		s.append("class A{\n");
147 		s.append("   void foo(int[] xs){\n");
148 		s.append("      for (int i : xs){\n");
149 		s.append("          break;");
150 		s.append("      }\n");
151 		s.append("   }\n");
152 		s.append("}\n");
153 		int offset= 1 + s.indexOf("break");//middle of word
154 		int length= 0;
155 		OccurrenceLocation[] ranges= { find(s, "for", 1), find(s, "}", 1) };
156 		checkSelection(s, offset, length, ranges);
157 	}
158 
159 	@Test
testBreakWhile()160 	public void testBreakWhile() throws Exception {
161 		StringBuffer s= new StringBuffer();
162 		s.append("class A{\n");
163 		s.append("  void foo(boolean b){\n");
164 		s.append("	    while (b) {\n");
165 		s.append("		   System.err.println(b);\n");
166 		s.append("		   break;\n");
167 		s.append("	    }\n");
168 		s.append("	}\n");
169 		s.append("}");
170 		int offset= 1 + s.indexOf("break");//middle of word
171 		int length= 0;
172 		OccurrenceLocation[] ranges= { find(s, "while", 1), find(s, "}", 1) };
173 		checkSelection(s, offset, length, ranges);
174 	}
175 
176 	@Test
testBreakDo()177 	public void testBreakDo() throws Exception {
178 		StringBuffer s= new StringBuffer();
179 		s.append("class A{\n");
180 		s.append("  void foo(boolean b){\n");
181 		s.append("	    do {\n");
182 		s.append("		   System.err.println(b);\n");
183 		s.append("		   break;\n");
184 		s.append("	    } while(b);\n");
185 		s.append("	}\n");
186 		s.append("}");
187 		int offset= 1 + s.indexOf("break");//middle of word
188 		int length= 0;
189 		OccurrenceLocation[] ranges= { find(s, "do", 1), find(s, ";", 3) };
190 		checkSelection(s, offset, length, ranges);
191 	}
192 
193 	@Test
testBreakSwitch()194 	public void testBreakSwitch() throws Exception {
195 		StringBuffer s= new StringBuffer();
196 		s.append("class A{\n");
197 		s.append("  void foo(int i){\n");
198 		s.append("    switch (i){\n");
199 		s.append("      case 1: System.err.println(i); break;\n");
200 		s.append("      default:System.out.println(i);\n");
201 		s.append("    }\n");
202 		s.append("  }\n");
203 		s.append("}\n");
204 		int offset= 1 + s.indexOf("break");//middle of word
205 		int length= 2;
206 		OccurrenceLocation[] ranges= { find(s, "switch", 1), find(s, "}", 1) };
207 		checkSelection(s, offset, length, ranges);
208 	}
209 
210 	@Test
testLabeledBreakFor()211 	public void testLabeledBreakFor() throws Exception {
212 		StringBuffer s= new StringBuffer();
213 		s.append("class A{\n");
214 		s.append("   void foo(int[] xs){\n");
215 		s.append("      bar: for (int i = 0; i < xs.length; i++) {\n");
216 		s.append("        do{\n");
217 		s.append("            break bar;");
218 		s.append("        }while (xs != null);\n");
219 		s.append("      }\n");
220 		s.append("   }\n");
221 		s.append("}\n");
222 		int offset= 1 + s.indexOf("break");//middle of word
223 		int length= 0;
224 		OccurrenceLocation[] ranges= { find(s, "bar", 1), find(s, "}", 2) };
225 		checkSelection(s, offset, length, ranges);
226 	}
227 
228 	@Test
testLabeledBreakFor1()229 	public void testLabeledBreakFor1() throws Exception {
230 		StringBuffer s= new StringBuffer();
231 		s.append("class A{\n");
232 		s.append("   void foo(int[] xs){\n");
233 		s.append("      bar: for (int i = 0; i < xs.length; i++) {\n");
234 		s.append("        baz: do{\n");
235 		s.append("            break bar;");
236 		s.append("        }while (xs != null);\n");
237 		s.append("      }\n");
238 		s.append("   }\n");
239 		s.append("}\n");
240 		int offset= 5 + s.indexOf("break");//after word
241 		int length= 0;
242 		OccurrenceLocation[] ranges= { find(s, "bar", 1), find(s, "}", 2) };
243 		checkSelection(s, offset, length, ranges);
244 	}
245 
246 	@Test
testBreakFor2()247 	public void testBreakFor2() throws Exception {
248 		StringBuffer s= new StringBuffer();
249 		s.append("class A{\n");
250 		s.append("   void foo(int[] xs){\n");
251 		s.append("      bar: for (int i = 0; i < xs.length; i++) {\n");
252 		s.append("        baz: do{\n");
253 		s.append("            break;");
254 		s.append("        }while (xs != null);\n");
255 		s.append("      }\n");
256 		s.append("   }\n");
257 		s.append("}\n");
258 		int offset= s.indexOf("break") + 2; // inside 'break'
259 		int length= 0;
260 		OccurrenceLocation[] ranges= { find(s, "baz", 1), find(s, ";", 4) };
261 		checkSelection(s, offset, length, ranges);
262 	}
263 
264 	@Test
testLabeledBreakIf()265 	public void testLabeledBreakIf() throws Exception {
266 		StringBuffer s= new StringBuffer();
267 		s.append("class A{\n");
268 		s.append("  public static void main(String[] args) {\n");
269 		s.append("    stay: if (true) {\n");
270 		s.append("      for (int i= 0; i < 5; i++) {\n");
271 		s.append("        System.out.println(i);\n");
272 		s.append("        if (i == 3)\n");
273 		s.append("          break stay;\n");
274 		s.append("      }\n");
275 		s.append("      System.out.println(\"after loop\");\n");
276 		s.append("      return;\n");
277 		s.append("    }\n");
278 		s.append("    System.out.println(\"Stayed!\");\n");
279 		s.append("  }\n");
280 		s.append("}\n");
281 		int offset= s.indexOf("break");//before word
282 		int length= 0;
283 		OccurrenceLocation[] ranges= { find(s, "stay", 1), find(s, "}", 2) };
284 		checkSelection(s, offset, length, ranges);
285 	}
286 
287 	@Test
testContinueFor()288 	public void testContinueFor() throws Exception {
289 		StringBuffer s= new StringBuffer();
290 		s.append("class A{\n");
291 		s.append("   void foo(int[] xs){\n");
292 		s.append("      for (int i = 0; i < xs.length; i++) {\n");
293 		s.append("          continue;");
294 		s.append("      }\n");
295 		s.append("   }\n");
296 		s.append("}\n");
297 		int offset= 1 + s.indexOf("continue");//middle of word
298 		int length= 0;
299 		OccurrenceLocation[] ranges= { find(s, "for", 1) };
300 		checkSelection(s, offset, length, ranges);
301 	}
302 
303 	@Test
testContinueForeach()304 	public void testContinueForeach() throws Exception {
305 		StringBuffer s= new StringBuffer();
306 		s.append("class A{\n");
307 		s.append("   void foo(int[] xs){\n");
308 		s.append("      for (int i : xs){\n");
309 		s.append("          continue;");
310 		s.append("      }\n");
311 		s.append("   }\n");
312 		s.append("}\n");
313 		int offset= 1 + s.indexOf("continue");//middle of word
314 		int length= 0;
315 		OccurrenceLocation[] ranges= { find(s, "for", 1) };
316 		checkSelection(s, offset, length, ranges);
317 	}
318 
319 	@Test
testContinueWhile()320 	public void testContinueWhile() throws Exception {
321 		StringBuffer s= new StringBuffer();
322 		s.append("class A{\n");
323 		s.append("  void foo(boolean b){\n");
324 		s.append("	    while (b) {\n");
325 		s.append("		   System.err.println(b);\n");
326 		s.append("		   continue;\n");
327 		s.append("	    }\n");
328 		s.append("	}\n");
329 		s.append("}");
330 		int offset= 1 + s.indexOf("continue");//middle of word
331 		int length= 0;
332 		OccurrenceLocation[] ranges= { find(s, "while", 1) };
333 		checkSelection(s, offset, length, ranges);
334 	}
335 
336 	@Test
testContinueDo()337 	public void testContinueDo() throws Exception {
338 		StringBuffer s= new StringBuffer();
339 		s.append("class A{\n");
340 		s.append("  void foo(boolean b){\n");
341 		s.append("	    do {\n");
342 		s.append("		   System.err.println(b);\n");
343 		s.append("		   continue;\n");
344 		s.append("	    } while(b);\n");
345 		s.append("	}\n");
346 		s.append("}");
347 		int offset= 1 + s.indexOf("continue");//middle of word
348 		int length= 0;
349 		OccurrenceLocation[] ranges= { find(s, "do", 1) };
350 		checkSelection(s, offset, length, ranges);
351 	}
352 
353 	//continue skips over switches
354 	@Test
testContinueSwitch()355 	public void testContinueSwitch() throws Exception {
356 		StringBuffer s= new StringBuffer();
357 		s.append("class A{\n");
358 		s.append("  void foo(int i){\n");
359 		s.append("    do{\n");
360 		s.append("       switch (i){\n");
361 		s.append("         case 1: System.err.println(i); continue;\n");
362 		s.append("         default:System.out.println(i);\n");
363 		s.append("       }\n");
364 		s.append("    }while(i != 9);\n");
365 		s.append("  }\n");
366 		s.append("}\n");
367 		int offset= 1 + s.indexOf("continue");//middle of word
368 		int length= 2;
369 		OccurrenceLocation[] ranges= { find(s, "do", 1) };
370 		checkSelection(s, offset, length, ranges);
371 	}
372 
373 	@Test
testLabeledContinueFor()374 	public void testLabeledContinueFor() throws Exception {
375 		StringBuffer s= new StringBuffer();
376 		s.append("class A{\n");
377 		s.append("   void foo(int[] xs){\n");
378 		s.append("      bar: for (int i = 0; i < xs.length; i++) {\n");
379 		s.append("        do{\n");
380 		s.append("            continue bar;");
381 		s.append("        }while (xs != null);\n");
382 		s.append("      }\n");
383 		s.append("   }\n");
384 		s.append("}\n");
385 		int offset= 1 + s.indexOf("continue");//middle of word
386 		int length= 0;
387 		OccurrenceLocation[] ranges= { find(s, "bar", 1) };
388 		checkSelection(s, offset, length, ranges);
389 	}
390 
391 	@Test
testLabeledContinueFor1()392 	public void testLabeledContinueFor1() throws Exception {
393 		StringBuffer s= new StringBuffer();
394 		s.append("class A{\n");
395 		s.append("   void foo(int[] xs){\n");
396 		s.append("      bar: for (int i = 0; i < xs.length; i++) {\n");
397 		s.append("        baz: do{\n");
398 		s.append("            continue bar;");
399 		s.append("        }while (xs != null);\n");
400 		s.append("      }\n");
401 		s.append("   }\n");
402 		s.append("}\n");
403 		int offset= 1 + s.indexOf("continue");//middle of word
404 		int length= 0;
405 		OccurrenceLocation[] ranges= { find(s, "bar", 1) };
406 		checkSelection(s, offset, length, ranges);
407 	}
408 
409 	@Test
testLabeledContinueFor2()410 	public void testLabeledContinueFor2() throws Exception {
411 		StringBuffer s= new StringBuffer();
412 		s.append("class A{\n");
413 		s.append("   void foo(int[] xs){\n");
414 		s.append("      bar: for (int i = 0; i < xs.length; i++) {\n");
415 		s.append("        baz: do{\n");
416 		s.append("            continue bar;");
417 		s.append("        }while (xs != null);\n");
418 		s.append("      }\n");
419 		s.append("   }\n");
420 		s.append("}\n");
421 		int offset= s.indexOf("continue bar;") + 1+ "continue ".length();//middle of label reference
422 		int length= 0;
423 		OccurrenceLocation[] ranges= { find(s, "bar", 1) };
424 		checkSelection(s, offset, length, ranges);
425 	}
426 
427 	@Test
testContinueFor2()428 	public void testContinueFor2() throws Exception {
429 		StringBuffer s= new StringBuffer();
430 		s.append("class A{\n");
431 		s.append("   void foo(int[] xs){\n");
432 		s.append("      bar: for (int i = 0; i < xs.length; i++) {\n");
433 		s.append("        baz: do{\n");
434 		s.append("            continue;");
435 		s.append("        }while (xs != null);\n");
436 		s.append("      }\n");
437 		s.append("   }\n");
438 		s.append("}\n");
439 		int offset= s.indexOf("continue;") + 2; // inside 'continue'
440 		int length= 0;
441 		OccurrenceLocation[] ranges= { find(s, "baz", 1) };
442 		checkSelection(s, offset, length, ranges);
443 	}
444 }
445