Added
Link Here
|
1 |
package org.eclipse.ui.tests.multieditor; |
2 |
|
3 |
import junit.framework.TestSuite; |
4 |
|
5 |
import org.eclipse.core.resources.IFile; |
6 |
import org.eclipse.core.resources.IProject; |
7 |
import org.eclipse.core.resources.IWorkspace; |
8 |
import org.eclipse.core.resources.ResourcesPlugin; |
9 |
import org.eclipse.core.runtime.CoreException; |
10 |
import org.eclipse.core.runtime.ILog; |
11 |
import org.eclipse.core.runtime.ILogListener; |
12 |
import org.eclipse.core.runtime.IStatus; |
13 |
import org.eclipse.jface.action.IContributionItem; |
14 |
import org.eclipse.jface.action.ToolBarContributionItem; |
15 |
import org.eclipse.jface.action.ToolBarManager; |
16 |
import org.eclipse.swt.widgets.Display; |
17 |
import org.eclipse.swt.widgets.ToolBar; |
18 |
import org.eclipse.swt.widgets.ToolItem; |
19 |
import org.eclipse.ui.IActionBars2; |
20 |
import org.eclipse.ui.IEditorInput; |
21 |
import org.eclipse.ui.IEditorPart; |
22 |
import org.eclipse.ui.IEditorRegistry; |
23 |
import org.eclipse.ui.IViewPart; |
24 |
import org.eclipse.ui.IWorkbenchPage; |
25 |
import org.eclipse.ui.IWorkbenchPart; |
26 |
import org.eclipse.ui.IWorkbenchWindow; |
27 |
import org.eclipse.ui.PartInitException; |
28 |
import org.eclipse.ui.internal.WorkbenchPage; |
29 |
import org.eclipse.ui.internal.WorkbenchPlugin; |
30 |
import org.eclipse.ui.part.FileEditorInput; |
31 |
import org.eclipse.ui.part.IContributedContentsView; |
32 |
import org.eclipse.ui.part.MultiEditor; |
33 |
import org.eclipse.ui.part.MultiEditorInput; |
34 |
import org.eclipse.ui.tests.util.CallHistory; |
35 |
import org.eclipse.ui.tests.util.UITestCase; |
36 |
|
37 |
/** |
38 |
* Test MultiEditor behaviour to highlight some of the broken functionality. |
39 |
* |
40 |
* @since 3.1 |
41 |
*/ |
42 |
public class MultiEditorTest extends UITestCase { |
43 |
private static final String PROJECT_NAME = "TiledEditorProject"; |
44 |
|
45 |
private static final String CONTENT_OUTLINE = "org.eclipse.ui.views.ContentOutline"; |
46 |
|
47 |
private static final String TESTEDITOR_COOLBAR = "org.eclipse.ui.tests.multieditor.TestEditor"; |
48 |
|
49 |
private static final String TILED_EDITOR_ID = "org.eclipse.ui.tests.multieditor.TiledEditor"; |
50 |
|
51 |
private static final String EDITOR_FAIL_LOG = "Unable to create editor ID "; |
52 |
|
53 |
// tiled editor test files |
54 |
private static final String TEST01_TXT = "test01.txt"; |
55 |
|
56 |
private static final String TEST02_TXT = "test02.txt"; |
57 |
|
58 |
private static final String TEST03_ETEST = "test03.etest"; |
59 |
|
60 |
private static final String TEST04_PROPERTIES = "test04.properties"; |
61 |
|
62 |
private static final String BUILD_XML = "build.xml"; |
63 |
|
64 |
public static TestSuite suite() { |
65 |
return new TestSuite(MultiEditorTest.class); |
66 |
} |
67 |
|
68 |
/** |
69 |
* Can catch a MultiEditor NPE on init. |
70 |
*/ |
71 |
private NPEListener fNpeListener; |
72 |
|
73 |
public MultiEditorTest(String tc) { |
74 |
super(tc); |
75 |
} |
76 |
|
77 |
/** |
78 |
* Test that the test tiled editor can be opened with a basic |
79 |
* MultiEditorInput with the same type of files. |
80 |
* |
81 |
* @throws Throwable |
82 |
* on an error |
83 |
*/ |
84 |
public void testOpenBasicEditor() throws Throwable { |
85 |
final String[] simpleFiles = { TEST01_TXT, TEST02_TXT }; |
86 |
|
87 |
setupNpe(); |
88 |
|
89 |
IWorkbenchWindow window = fWorkbench.getActiveWorkbenchWindow(); |
90 |
IWorkbenchPage page = window.getActivePage(); |
91 |
|
92 |
IProject testProject = findOrCreateProject(PROJECT_NAME); |
93 |
|
94 |
MultiEditorInput input = generateEditorInput(simpleFiles, testProject); |
95 |
|
96 |
// validate there are no NullPointerExceptions during editor |
97 |
// initialization |
98 |
openAndValidateEditor(page, input); |
99 |
} |
100 |
|
101 |
/** |
102 |
* Test that the public methods in TiledEditor (and MultiEditor) are called |
103 |
* in the correct order from 3.0 to 3.1. |
104 |
* |
105 |
* @throws Throwable |
106 |
*/ |
107 |
public void testOpenTestFile() throws Throwable { |
108 |
final String[] simpleFiles = { TEST01_TXT, TEST03_ETEST }; |
109 |
|
110 |
setupNpe(); |
111 |
|
112 |
IWorkbenchWindow window = fWorkbench.getActiveWorkbenchWindow(); |
113 |
WorkbenchPage page = (WorkbenchPage) window.getActivePage(); |
114 |
|
115 |
IProject testProject = findOrCreateProject(PROJECT_NAME); |
116 |
|
117 |
MultiEditorInput input = generateEditorInput(simpleFiles, testProject); |
118 |
|
119 |
// catches the framework NPE |
120 |
IEditorPart editor = openAndValidateEditor(page, input); |
121 |
|
122 |
// did we get a multieditor back? |
123 |
assertTrue(editor instanceof MultiEditor); |
124 |
MultiEditor multiEditor = (MultiEditor) editor; |
125 |
|
126 |
chewUpEvents(); |
127 |
|
128 |
// swap focus to the last editor, which is the test editor |
129 |
// with the test coolbar contribution |
130 |
IEditorPart[] innerEditors = multiEditor.getInnerEditors(); |
131 |
innerEditors[innerEditors.length - 1].setFocus(); |
132 |
|
133 |
chewUpEvents(); |
134 |
|
135 |
final String[] publicMethodTrace = { "init", "init", |
136 |
"createPartControl", "createInnerPartControl", |
137 |
"updateInnerEditorTitle", "createInnerPartControl", |
138 |
"updateInnerEditorTitle", "setFocus", "updateGradient", |
139 |
"updateGradient", "updateGradient", "updateGradient", |
140 |
"setFocus", "updateGradient", "updateGradient", |
141 |
"updateGradient", }; |
142 |
assertTrue("The public methods weren't called in the correct order", |
143 |
((TiledEditor) multiEditor).callHistory |
144 |
.verifyOrder(publicMethodTrace)); |
145 |
} |
146 |
|
147 |
/** |
148 |
* Test that various items in the workbench are updated when focus moves |
149 |
* through the different inner editors. |
150 |
* |
151 |
* @throws Throwable |
152 |
* on an error |
153 |
*/ |
154 |
public void testOpenBuildFile() throws Throwable { |
155 |
final String[] simpleFiles = { TEST01_TXT, TEST02_TXT, |
156 |
TEST04_PROPERTIES, BUILD_XML, TEST03_ETEST }; |
157 |
|
158 |
setupNpe(); |
159 |
|
160 |
IWorkbenchWindow window = fWorkbench.getActiveWorkbenchWindow(); |
161 |
WorkbenchPage page = (WorkbenchPage) window.getActivePage(); |
162 |
|
163 |
IProject testProject = findOrCreateProject(PROJECT_NAME); |
164 |
|
165 |
MultiEditorInput input = generateEditorInput(simpleFiles, testProject); |
166 |
|
167 |
// catches the framework NPE |
168 |
IEditorPart editor = openAndValidateEditor(page, input); |
169 |
|
170 |
// did we get a multieditor back? |
171 |
assertTrue(editor instanceof MultiEditor); |
172 |
MultiEditor multiEditor = (MultiEditor) editor; |
173 |
|
174 |
chewUpEvents(); |
175 |
|
176 |
// get access to the appropriate coolbar |
177 |
IContributionItem contribution = findMyCoolBar(page); |
178 |
|
179 |
// our test editor contribution should not be visible |
180 |
// but it should be enabled |
181 |
assertFalse("We open in the default text editor", contribution |
182 |
.isVisible()); |
183 |
assertTrue("And we're good to go", contribution.isEnabled()); |
184 |
|
185 |
// swap focus to the last editor, which is the test editor |
186 |
// with the test coolbar contribution |
187 |
IEditorPart[] innerEditors = multiEditor.getInnerEditors(); |
188 |
innerEditors[innerEditors.length - 1].setFocus(); |
189 |
|
190 |
chewUpEvents(); |
191 |
|
192 |
// our test editor contribution should now be visible and |
193 |
// enabled |
194 |
assertTrue("We are in the test editor", contribution.isVisible()); |
195 |
assertTrue("And we're good to go", contribution.isEnabled()); |
196 |
|
197 |
// Swap to the second last editor, which should be the ant |
198 |
// build editor. |
199 |
innerEditors[innerEditors.length - 2].setFocus(); |
200 |
chewUpEvents(); |
201 |
|
202 |
// get the outline view part |
203 |
IViewPart outline = window.getActivePage().findView(CONTENT_OUTLINE); |
204 |
assertNotNull(outline); |
205 |
|
206 |
// find out who is contributing the outline view. |
207 |
IContributedContentsView view = (IContributedContentsView) outline |
208 |
.getAdapter(IContributedContentsView.class); |
209 |
IWorkbenchPart part = view.getContributingPart(); |
210 |
assertNotNull("The Outline view has not been updated by the editor", |
211 |
part); |
212 |
assertTrue("The Outline view is not talking to an editor", |
213 |
part instanceof IEditorPart); |
214 |
|
215 |
IEditorPart outlineEditor = (IEditorPart) part; |
216 |
|
217 |
// the active inner editor (the ant editor) should also |
218 |
// be the outline editor contributor ... this works in |
219 |
// 3.0, fails in 3.1 |
220 |
assertEquals("The Outline view is not talking to the correct editor", |
221 |
multiEditor.getActiveEditor(), outlineEditor); |
222 |
} |
223 |
|
224 |
/** |
225 |
* Return the test editor coolbar. |
226 |
* |
227 |
* @param page |
228 |
* the workbench page |
229 |
* @return the IContributionItem for the test editor cool bar. |
230 |
*/ |
231 |
private IContributionItem findMyCoolBar(WorkbenchPage page) { |
232 |
IContributionItem contribution = ((IActionBars2) page.getActionBars()) |
233 |
.getCoolBarManager().find(TESTEDITOR_COOLBAR); |
234 |
assertNotNull(contribution); |
235 |
|
236 |
return contribution; |
237 |
} |
238 |
|
239 |
/** |
240 |
* Create the project to work in. If it already exists, just open it. |
241 |
* |
242 |
* @param projectName |
243 |
* the name of the project to create |
244 |
* @return the newly opened project |
245 |
* @throws CoreException |
246 |
*/ |
247 |
private IProject findOrCreateProject(String projectName) |
248 |
throws CoreException { |
249 |
IWorkspace workspace = ResourcesPlugin.getWorkspace(); |
250 |
IProject testProject = workspace.getRoot().getProject(projectName); |
251 |
if (!testProject.exists()) { |
252 |
testProject.create(null); |
253 |
} |
254 |
testProject.open(null); |
255 |
return testProject; |
256 |
} |
257 |
|
258 |
/** |
259 |
* Internal printing method, only used for investigation. |
260 |
* |
261 |
* @param page |
262 |
* the workbench page |
263 |
*/ |
264 |
private void checkView(WorkbenchPage page) { |
265 |
IViewPart[] views = page.getViews(); |
266 |
for (int i = 0; i < views.length; ++i) { |
267 |
System.err.println("view: " + views[i].getViewSite().getId() + "/" |
268 |
+ views[i].getViewSite().getRegisteredName()); |
269 |
} |
270 |
} |
271 |
|
272 |
/** |
273 |
* Print the call history to console. Only used for investigation. |
274 |
* |
275 |
* @param history |
276 |
* the editor call history object. |
277 |
*/ |
278 |
private void listHistory(CallHistory history) { |
279 |
history.printToConsole(); |
280 |
} |
281 |
|
282 |
/** |
283 |
* List bits and internals of the coolbar manager contribution items. Only |
284 |
* used for investigation. |
285 |
* |
286 |
* @param page |
287 |
* the workbench page |
288 |
*/ |
289 |
private void listItems(WorkbenchPage page) { |
290 |
checkView(page); |
291 |
IContributionItem[] items = ((IActionBars2) page.getActionBars()) |
292 |
.getCoolBarManager().getItems(); |
293 |
System.err.println("Length: " + items.length); |
294 |
for (int i = 0; i < items.length; ++i) { |
295 |
System.err.println("" + items[i].isEnabled() + ":" |
296 |
+ items[i].isVisible() + " " + items[i].getId() + "\n\t" |
297 |
+ items[i].getClass().getName()); |
298 |
if (items[i] instanceof ToolBarContributionItem) { |
299 |
displayItem(items[i]); |
300 |
} |
301 |
} |
302 |
System.err.println("----"); |
303 |
} |
304 |
|
305 |
/** |
306 |
* Display bits of contribution item internals to the console. Only used for |
307 |
* investigation. |
308 |
* |
309 |
* @param contributionItem |
310 |
* the IContributionItem to display |
311 |
*/ |
312 |
private void displayItem(IContributionItem contributionItem) { |
313 |
ToolBarManager toolBarManager = (ToolBarManager) ((ToolBarContributionItem) contributionItem) |
314 |
.getToolBarManager(); |
315 |
ToolBar bar = toolBarManager.getControl(); |
316 |
if (bar == null) { |
317 |
System.err.println("\tInfo-items: -1"); |
318 |
} else { |
319 |
System.err.println("\tInfo-items: " + bar.getItemCount() + "/" |
320 |
+ bar.getEnabled() + "/" + bar.isEnabled() + "/" |
321 |
+ bar.isVisible()); |
322 |
ToolItem[] tools = bar.getItems(); |
323 |
for (int t = 0; t < tools.length; ++t) { |
324 |
System.err.println("\t\titem: " + tools[t].getEnabled() + " " |
325 |
+ tools[t].getToolTipText()); |
326 |
} |
327 |
} |
328 |
} |
329 |
|
330 |
/** |
331 |
* After an internal action, see if there are any outstanding SWT events. |
332 |
*/ |
333 |
private void chewUpEvents() throws InterruptedException { |
334 |
Thread.sleep(250); |
335 |
Display display = Display.getCurrent(); |
336 |
while (display.readAndDispatch()) |
337 |
; |
338 |
} |
339 |
|
340 |
/** |
341 |
* Open the test editor. It does basic validation that there is no |
342 |
* NullPointerException during initialization. |
343 |
* |
344 |
* @param page |
345 |
* the workbench page |
346 |
* @param input |
347 |
* the editor input with multiple files |
348 |
* @return the MultiEditor |
349 |
* @throws PartInitException |
350 |
*/ |
351 |
private IEditorPart openAndValidateEditor(IWorkbenchPage page, |
352 |
MultiEditorInput input) throws PartInitException { |
353 |
IEditorPart editorPart = page.openEditor(input, |
354 |
MultiEditorTest.TILED_EDITOR_ID); |
355 |
assertNotNull(editorPart); |
356 |
|
357 |
// 3.1.0 only |
358 |
// assertFalse("The editor never actualized", |
359 |
// editorPart instanceof ErrorEditorPart); |
360 |
|
361 |
assertTrue("Unable to create " + MultiEditorTest.TILED_EDITOR_ID, |
362 |
fNpeListener.noNPE); |
363 |
return editorPart; |
364 |
} |
365 |
|
366 |
/** |
367 |
* Set up to catch any editor initialization NullPointerExceptions. |
368 |
* |
369 |
*/ |
370 |
private void setupNpe() { |
371 |
final ILog log = WorkbenchPlugin.getDefault().getLog(); |
372 |
fNpeListener = new NPEListener(); |
373 |
log.addLogListener(fNpeListener); |
374 |
} |
375 |
|
376 |
/** |
377 |
* Create the multi editor input in the given project. Creates the files in |
378 |
* the project from template files in the classpath if they don't already |
379 |
* exist. |
380 |
* |
381 |
* @param simpleFiles |
382 |
* the array of filenames to copy over |
383 |
* @param testProject |
384 |
* the project to create the files in |
385 |
* @return the editor input used to open the multieditor |
386 |
* @throws CoreException |
387 |
*/ |
388 |
private MultiEditorInput generateEditorInput(String[] simpleFiles, |
389 |
IProject testProject) throws CoreException { |
390 |
String[] ids = new String[simpleFiles.length]; |
391 |
IEditorInput[] inputs = new IEditorInput[simpleFiles.length]; |
392 |
IEditorRegistry registry = fWorkbench.getEditorRegistry(); |
393 |
|
394 |
for (int f = 0; f < simpleFiles.length; ++f) { |
395 |
IFile f1 = testProject.getFile(simpleFiles[f]); |
396 |
if (!f1.exists()) { |
397 |
f1.create(getClass().getResourceAsStream(simpleFiles[f]), true, |
398 |
null); |
399 |
} |
400 |
ids[f] = registry.getDefaultEditor(f1.getName()).getId(); |
401 |
inputs[f] = new FileEditorInput(f1); |
402 |
} |
403 |
|
404 |
MultiEditorInput input = new MultiEditorInput(ids, inputs); |
405 |
return input; |
406 |
} |
407 |
|
408 |
/** |
409 |
* Close any editors at the end of a test, so the next test can be clean. |
410 |
*/ |
411 |
protected void doTearDown() throws Exception { |
412 |
fWorkbench.getActiveWorkbenchWindow().getActivePage().closeAllEditors( |
413 |
false); |
414 |
super.doTearDown(); |
415 |
} |
416 |
|
417 |
/** |
418 |
* Listens for the standard message that indicates the MultiEditor failed |
419 |
* ... usually caused by incorrect framework initialization that doesn't set |
420 |
* the innerChildren. |
421 |
* |
422 |
* @since 3.1 |
423 |
* |
424 |
*/ |
425 |
public static class NPEListener implements ILogListener { |
426 |
public boolean noNPE = true; |
427 |
|
428 |
public void logging(IStatus status, String plugin) { |
429 |
String msg = status.getMessage(); |
430 |
if (msg != null |
431 |
&& msg.indexOf(MultiEditorTest.EDITOR_FAIL_LOG |
432 |
+ MultiEditorTest.TILED_EDITOR_ID) >= 0) { |
433 |
noNPE = false; |
434 |
} |
435 |
} |
436 |
} |
437 |
} |