1 /*******************************************************************************
2  * Copyright (c) 2008, 2015, 2019 Oakland Software Incorporated 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  *     Oakland Software Incorporated - initial API and implementation
13  *.....IBM Corporation - fixed dead code warning
14  *     Fair Issac Corp - bug 287103 - NCSLabelProvider does not properly handle overrides
15  *     Thibault Le Ouay <thibaultleouay@gmail.com> - Bug 457870
16  *     Stefan Winkler <stefan@winklerweb.net> - bug 178019 - CNF Tooltip support
17  *******************************************************************************/
18 package org.eclipse.ui.tests.navigator;
19 
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 
24 import org.eclipse.core.resources.IFile;
25 import org.eclipse.jface.viewers.ILabelProvider;
26 import org.eclipse.jface.viewers.IToolTipProvider;
27 import org.eclipse.jface.viewers.ITreeContentProvider;
28 import org.eclipse.swt.widgets.TreeItem;
29 import org.eclipse.ui.internal.navigator.extensions.NavigatorContentExtension;
30 import org.eclipse.ui.tests.harness.util.DisplayHelper;
31 import org.eclipse.ui.tests.navigator.extension.TestEmptyContentProvider;
32 import org.eclipse.ui.tests.navigator.extension.TestLabelProvider;
33 import org.eclipse.ui.tests.navigator.extension.TestLabelProviderBlank;
34 import org.eclipse.ui.tests.navigator.extension.TestLabelProviderCyan;
35 import org.eclipse.ui.tests.navigator.extension.TestLabelProviderStyledGreen;
36 import org.eclipse.ui.tests.navigator.extension.TrackingLabelProvider;
37 import org.junit.Test;
38 
39 public class LabelProviderTest extends NavigatorTestBase {
40 
41 	private static final boolean PRINT_DEBUG_INFO = false;
42 	private static final boolean SLEEP_LONG = false;
43 
LabelProviderTest()44 	public LabelProviderTest() {
45 		_navigatorInstanceId = "org.eclipse.ui.tests.navigator.OverrideTestView";
46 	}
47 
48 	private static final int NONE = 0;
49 	private static final int OVERRIDDEN = 1;
50 	private static final int OVERRIDING = 2;
51 	private static final int BOTH = 3;
52 
53 	private static final boolean BLANK = true;
54 	private static final boolean NULL = false;
55 
56 	private static final String PLAIN = "Plain";
57 
setBlank(String cpToGet, boolean blank)58 	private void setBlank(String cpToGet, boolean blank) {
59 		NavigatorContentExtension ext = (NavigatorContentExtension) _contentService
60 				.getContentExtensionById(cpToGet);
61 		TestLabelProvider tp = (TestLabelProvider) ext.getLabelProvider();
62 		if (blank)
63 			tp._blank = true;
64 		else
65 			tp._null = true;
66 
67 	}
68 
69 	// Bug 289090 label provider returning blank in getText() not properly
70 	// skipped
71 	// Bug 296253 blank label provider should be allowed if nothing better found
blankLabelProviderOverride(int nce, boolean blank, String suffix)72 	public void blankLabelProviderOverride(int nce, boolean blank, String suffix) throws Exception {
73 
74 		String overriddenCp = TEST_CONTENT_OVERRIDDEN1 + suffix; // Red
75 		String overrideCp = TEST_CONTENT_OVERRIDE1 + suffix; // Green
76 
77 		String checkColor = "Green";
78 
79 		switch (nce) {
80 		case NONE:
81 			break;
82 		case OVERRIDDEN:
83 			setBlank(overriddenCp, blank);
84 			break;
85 		case OVERRIDING:
86 			checkColor = "Red";
87 			setBlank(overrideCp, blank);
88 			break;
89 		case BOTH:
90 			setBlank(overriddenCp, blank);
91 			setBlank(overrideCp, blank);
92 			break;
93 		}
94 
95 		_contentService.bindExtensions(new String[] { overriddenCp, overrideCp }, false);
96 		_contentService.getActivationService().activateExtensions(
97 				new String[] { overrideCp, overriddenCp }, true);
98 
99 		refreshViewer();
100 
101 		// This tests the getStyledText() method
102 		TreeItem[] rootItems = _viewer.getTree().getItems();
103 
104 		// Also test the raw ILabelProvider which uses the getText() method
105 		ILabelProvider lp = _contentService.createCommonLabelProvider();
106 		String lpText = lp.getText(rootItems[0].getData());
107 
108 		if (nce == BOTH) {
109 			if (!rootItems[0].getText().isEmpty())
110 				fail("Wrong text: " + rootItems[0].getText());
111 
112 			if (blank) {
113 				if (!lpText.isEmpty())
114 					fail("Wrong text from ILabelProvider: " + lpText);
115 			} else {
116 				if (lpText != null)
117 					fail("Wrong text from ILabelProvider: " + lpText);
118 			}
119 		} else {
120 			if (!rootItems[0].getText().startsWith(checkColor))
121 				fail("Wrong text: " + rootItems[0].getText());
122 			if (!lpText.startsWith(checkColor))
123 				fail("Wrong text from ILabelProvider: " + lpText);
124 		}
125 	}
126 
127 	@Test
testBlankLabelProviderOverrideNone()128 	public void testBlankLabelProviderOverrideNone() throws Exception {
129 		blankLabelProviderOverride(NONE, BLANK, "");
130 	}
131 
132 	@Test
testNullLabelProviderOverrideNone()133 	public void testNullLabelProviderOverrideNone() throws Exception {
134 		blankLabelProviderOverride(NONE, NULL, "");
135 	}
136 
137 	@Test
testPlainBlankLabelProviderOverrideNone()138 	public void testPlainBlankLabelProviderOverrideNone() throws Exception {
139 		blankLabelProviderOverride(NONE, BLANK, PLAIN);
140 	}
141 
142 	@Test
testPlainNullLabelProviderOverrideNone()143 	public void testPlainNullLabelProviderOverrideNone() throws Exception {
144 		blankLabelProviderOverride(NONE, NULL, PLAIN);
145 	}
146 
147 	@Test
testBlankLabelProviderOverride1()148 	public void testBlankLabelProviderOverride1() throws Exception {
149 		blankLabelProviderOverride(OVERRIDDEN, BLANK, "");
150 	}
151 
152 	@Test
testNullLabelProviderOverride1()153 	public void testNullLabelProviderOverride1() throws Exception {
154 		blankLabelProviderOverride(OVERRIDDEN, NULL, "");
155 	}
156 
157 	@Test
testPlainBlankLabelProviderOverride1()158 	public void testPlainBlankLabelProviderOverride1() throws Exception {
159 		blankLabelProviderOverride(OVERRIDDEN, BLANK, PLAIN);
160 	}
161 
162 	@Test
testPlainNullLabelProviderOverride1()163 	public void testPlainNullLabelProviderOverride1() throws Exception {
164 		blankLabelProviderOverride(OVERRIDDEN, NULL, PLAIN);
165 	}
166 
167 	@Test
testBlankLabelProviderOverride2()168 	public void testBlankLabelProviderOverride2() throws Exception {
169 		blankLabelProviderOverride(OVERRIDING, BLANK, "");
170 	}
171 
172 	@Test
testNullLabelProviderOverride2()173 	public void testNullLabelProviderOverride2() throws Exception {
174 		blankLabelProviderOverride(OVERRIDING, NULL, "");
175 	}
176 
177 	@Test
testPlainBlankLabelProviderOverride2()178 	public void testPlainBlankLabelProviderOverride2() throws Exception {
179 		blankLabelProviderOverride(OVERRIDING, BLANK, PLAIN);
180 	}
181 
182 	@Test
testPlainNullLabelProviderOverride2()183 	public void testPlainNullLabelProviderOverride2() throws Exception {
184 		blankLabelProviderOverride(OVERRIDING, NULL, PLAIN);
185 	}
186 
187 	@Test
testBlankLabelProviderBoth()188 	public void testBlankLabelProviderBoth() throws Exception {
189 		blankLabelProviderOverride(BOTH, BLANK, "");
190 	}
191 
192 	@Test
testNullLabelProviderBoth()193 	public void testNullLabelProviderBoth() throws Exception {
194 		blankLabelProviderOverride(BOTH, NULL, "");
195 	}
196 
197 	@Test
testPlainBlankLabelProviderBoth()198 	public void testPlainBlankLabelProviderBoth() throws Exception {
199 		blankLabelProviderOverride(BOTH, BLANK, PLAIN);
200 	}
201 
202 	@Test
testPlainNullLabelProviderBoth()203 	public void testPlainNullLabelProviderBoth() throws Exception {
204 		blankLabelProviderOverride(BOTH, NULL, PLAIN);
205 	}
206 
207 	// bug 252293 [CommonNavigator] LabelProviders do not obey override rules
208 	@Test
testSimpleResFirst()209 	public void testSimpleResFirst() throws Exception {
210 
211 		_contentService.bindExtensions(new String[] { TEST_CONTENT_OVERRIDDEN1,
212 				TEST_CONTENT_OVERRIDE1 }, false);
213 		_contentService.getActivationService().activateExtensions(
214 				new String[] { TEST_CONTENT_OVERRIDE1, TEST_CONTENT_OVERRIDDEN1 }, true);
215 
216 		refreshViewer();
217 
218 		TreeItem[] rootItems = _viewer.getTree().getItems();
219 		checkItems(rootItems, TestLabelProviderStyledGreen.instance);
220 	}
221 
222 	/**
223 	 * E{low} overrides D{low} overrides B{normal} overrides A F{high} overrides
224 	 * C{low} overrides A G{normal} overrides C{low}.
225 	 *
226 	 * F is the highest priority and not overridden, so it's first.
227 	 * B is next, but is overridden by E and D. So we have FEDB. Then A is processed
228 	 * which is overridden by B and C which is overridden by B, so we have FEDBGCA.
229 	 */
230 	@Test
testOverrideChain()231 	public void testOverrideChain() throws Exception {
232 		final String[] EXTENSIONS = new String[] { TEST_CONTENT_TRACKING_LABEL + ".A",
233 				TEST_CONTENT_TRACKING_LABEL + ".B", TEST_CONTENT_TRACKING_LABEL + ".C",
234 				TEST_CONTENT_TRACKING_LABEL + ".D", TEST_CONTENT_TRACKING_LABEL + ".E",
235 				TEST_CONTENT_TRACKING_LABEL + ".F", TEST_CONTENT_TRACKING_LABEL + ".G" };
236 		_contentService.bindExtensions(EXTENSIONS, true);
237 		_contentService.getActivationService().activateExtensions(EXTENSIONS, true);
238 
239 		refreshViewer();
240 		_viewer.getTree().getItems();
241 
242 		TrackingLabelProvider.resetQueries();
243 
244 		// Time for the decorating label provider to settle down
245 		DisplayHelper.sleep(200);
246 
247 		refreshViewer();
248 
249 		// The label provider (sync runs) and then the decorating label provider
250 		// runs (in something like every 100ms)
251 		// Give time for both and expect both to have happened.
252 		DisplayHelper.sleep(200);
253 
254 		//final String EXPECTED = "FEDBGCA";
255 		//final String EXPECTED = "FGEDBCA";
256 		if (PRINT_DEBUG_INFO)
257 			System.out.println("Map: " + TrackingLabelProvider.styledTextQueries);
258 		String queries = (String) TrackingLabelProvider.styledTextQueries.get(_project);
259 		// This can happen multiple times depending on when the decorating label
260 		// provider runs, so just make sure the sequence is right
261 		assertTrue("F has the highest priority", queries.startsWith("F"));
262 		assertBefore(queries, 'C', 'A');
263 		assertBefore(queries, 'B', 'A');
264 		assertBefore(queries, 'D', 'B');
265 		assertBefore(queries, 'E', 'D');
266 		assertBefore(queries, 'F', 'C');
267 		assertBefore(queries, 'G', 'C');
268 	}
269 
270 	/**
271 	 * @param queries
272 	 * @param firstChar
273 	 * @param secondChar
274 	 */
assertBefore(String queries, char firstChar, char secondChar)275 	private void assertBefore(String queries, char firstChar, char secondChar) {
276 		boolean first = false;
277 		final int LEN = queries.length();
278 		for (int i=0; i<LEN; i++) {
279 			char cur = queries.charAt(i);
280 			if (cur == firstChar) {
281 				first = true;
282 			}
283 			if (cur == secondChar) {
284 				assertTrue("Failed to find " + firstChar + " before " + secondChar + " in " + queries, first);
285 				return;
286 			}
287 		}
288 	}
289 
290 	// bug 252293 [CommonNavigator] LabelProviders do not obey override rules
291 	@Test
testSimpleResLast()292 	public void testSimpleResLast() throws Exception {
293 		_contentService.bindExtensions(new String[] { TEST_CONTENT_OVERRIDDEN2,
294 				TEST_CONTENT_OVERRIDE2 }, false);
295 		_contentService.getActivationService().activateExtensions(
296 				new String[] { TEST_CONTENT_OVERRIDDEN2, TEST_CONTENT_OVERRIDE2 }, true);
297 
298 		refreshViewer();
299 
300 		if (SLEEP_LONG)
301 			DisplayHelper.sleep(10000000);
302 
303 		TreeItem[] rootItems = _viewer.getTree().getItems();
304 		checkItems(rootItems, TestLabelProviderCyan.instance);
305 	}
306 
307 	@Test
testOverrideAdd()308 	public void testOverrideAdd() throws Exception {
309 		_contentService.bindExtensions(new String[] { TEST_CONTENT_OVERRIDDEN2,
310 				TEST_CONTENT_OVERRIDE2 }, false);
311 		_contentService.getActivationService().activateExtensions(
312 				new String[] { TEST_CONTENT_OVERRIDDEN2, TEST_CONTENT_OVERRIDE2 }, true);
313 
314 		refreshViewer();
315 
316 		// Try manually adding
317 		_viewer.expandToLevel(_project, 3);
318 		IFile f = _project.getFile("newfile");
319 		_viewer.add(_project, new Object[] { f });
320 
321 		if (SLEEP_LONG)
322 			DisplayHelper.sleep(10000000);
323 
324 		TreeItem[] rootItems = _viewer.getTree().getItems();
325 		checkItems(rootItems, TestLabelProviderCyan.instance);
326 	}
327 
328 	// Bug 299438 activating extensions does not properly refresh
329 	@Test
testChangeActivation()330 	public void testChangeActivation() throws Exception {
331 		TreeItem[] rootItems = _viewer.getTree().getItems();
332 		checkItems(rootItems, TestLabelProviderStyledGreen.instance);
333 
334 		_contentService.bindExtensions(new String[] { TEST_CONTENT_OVERRIDDEN2,
335 				TEST_CONTENT_OVERRIDE2 }, false);
336 		_contentService.getActivationService().activateExtensions(
337 				new String[] { TEST_CONTENT_OVERRIDDEN2, TEST_CONTENT_OVERRIDE2 }, true);
338 
339 		_viewer.expandAll();
340 
341 		//System.out.println(System.currentTimeMillis() + " after expand");
342 
343 		// Let the label provider refresh - wait up to 60 seconds
344 		for (int i = 0; i < 1200; i++) {
345 			rootItems = _viewer.getTree().getItems();
346 			//System.out.println("checking text: " + rootItems[0].getText());
347 			if (rootItems[0].getBackground(0).equals(TestLabelProviderCyan.instance.backgroundColor))
348 				break;
349 			//System.out.println(System.currentTimeMillis() + " before sleep " + i);
350 			DisplayHelper.sleep(50);
351 		}
352 
353 		//System.out.println(System.currentTimeMillis() + " after sleep");
354 
355 		if (SLEEP_LONG)
356 			DisplayHelper.sleep(10000000);
357 
358 		// Wait a little bit still to give the rest of the tree time to refresh
359 		DisplayHelper.sleep(500);
360 
361 		rootItems = _viewer.getTree().getItems();
362 		checkItems(rootItems, TestLabelProviderCyan.instance);
363 	}
364 
365 	// Make sure that it finds label providers that are in overridden content
366 	// extensions
367 	// if none of the label providers from the desired content extensions return
368 	// anything
369 	@Test
testUsingOverriddenLabelProvider()370 	public void testUsingOverriddenLabelProvider() throws Exception {
371 
372 		_contentService.bindExtensions(new String[] { TEST_CONTENT_OVERRIDDEN2,
373 				TEST_CONTENT_OVERRIDE2_BLANK }, true);
374 		_contentService.getActivationService().activateExtensions(
375 				new String[] { TEST_CONTENT_OVERRIDDEN2, TEST_CONTENT_OVERRIDE2_BLANK }, true);
376 
377 		refreshViewer();
378 
379 		TreeItem[] rootItems = _viewer.getTree().getItems();
380 
381 		if (SLEEP_LONG)
382 			DisplayHelper.sleep(10000000);
383 
384 		// But we get the text from the overridden label provider
385 		if (!rootItems[0].getText().startsWith("Blue"))
386 			fail("Wrong text: " + rootItems[0].getText());
387 
388 		// We get the everything else from the blank label provider
389 		checkItems(rootItems, TestLabelProviderBlank.instance, ALL, !TEXT);
390 	}
391 
392 	// Bug 295803 Source of contribution set to lowest priority NCE
393 	@Test
testMultiNceSameObject()394 	public void testMultiNceSameObject() throws Exception {
395 
396 		_contentService.bindExtensions(new String[] { TEST_CONTENT_OVERRIDDEN1, COMMON_NAVIGATOR_RESOURCE_EXT }, true);
397 		// Just two different ones, they don't override, the label provider
398 		// should be associated with the higher priority extension that
399 		// contributed the object.
400 		_contentService.getActivationService().activateExtensions(
401 				new String[] { TEST_CONTENT_OVERRIDDEN1, COMMON_NAVIGATOR_RESOURCE_EXT }, true);
402 
403 		refreshViewer();
404 
405 		TreeItem[] rootItems = _viewer.getTree().getItems();
406 
407 		// DisplayHelper.sleep(10000000);
408 
409 		// But we get the text from the overridden label provider
410 		if (!rootItems[0].getText().equals("p1"))
411 			fail("Wrong text: " + rootItems[0].getText());
412 	}
413 
414 	// Bug 307132 label provider priority not respected
415 	@Test
testLabelProviderPriority()416 	public void testLabelProviderPriority() throws Exception {
417 
418 		_contentService.bindExtensions(new String[] { TEST_CONTENT_EMPTY, COMMON_NAVIGATOR_RESOURCE_EXT }, true);
419 		// Just two different ones, they don't override, the label provider
420 		// should be associated with the higher priority extension that
421 		// contributed the object.
422 		_contentService.getActivationService().activateExtensions(
423 				new String[] { TEST_CONTENT_EMPTY, COMMON_NAVIGATOR_RESOURCE_EXT }, true);
424 
425 		refreshViewer();
426 
427 		TreeItem[] rootItems = _viewer.getTree().getItems();
428 
429 		//DisplayHelper.sleep(10000000);
430 
431 		// The empty content provider provides the label at a higher priority
432 		// than the resource content provider
433 		assertEquals(TestLabelProviderCyan.instance.image, rootItems[0].getImage(0));
434 	}
435 
436 	// Bug 189986 add SafeRunner for everything
437 	@Test
testLabelProviderThrow()438 	public void testLabelProviderThrow() throws Exception {
439 
440 		_contentService.bindExtensions(new String[] { TEST_CONTENT_EMPTY, COMMON_NAVIGATOR_RESOURCE_EXT }, true);
441 		_contentService.getActivationService().activateExtensions(
442 				new String[] { TEST_CONTENT_EMPTY, COMMON_NAVIGATOR_RESOURCE_EXT }, true);
443 
444 		TestLabelProvider._throw = true;
445 		TestEmptyContentProvider._throw = true;
446 
447 		refreshViewer();
448 		// Have to look at the log to see a bunch of stuff thrown
449 	}
450 
451 	@Test
testLabelProviderSupportsTooltip()452 	public void testLabelProviderSupportsTooltip() throws Exception {
453 		_contentService.bindExtensions(new String[] { TEST_CONTENT_TOOLTIPS, COMMON_NAVIGATOR_RESOURCE_EXT }, true);
454 		_contentService.getActivationService()
455 				.activateExtensions(new String[] { TEST_CONTENT_TOOLTIPS, COMMON_NAVIGATOR_RESOURCE_EXT }, true);
456 
457 		refreshViewer();
458 
459 		assertTrue(_viewer.getLabelProvider() instanceof IToolTipProvider);
460 		IToolTipProvider tooltipProvider = (IToolTipProvider) _viewer.getLabelProvider();
461 
462 		assertTrue(_viewer.getContentProvider() instanceof ITreeContentProvider);
463 		ITreeContentProvider contentProvider = (ITreeContentProvider) _viewer.getContentProvider();
464 
465 		Object[] rootElements = contentProvider.getElements(_viewer.getInput());
466 
467 		for (Object element : rootElements) {
468 			assertTrue(tooltipProvider.getToolTipText(element).startsWith("ToolTip"));
469 		}
470 	}
471 }
472