View Javadoc

1   // Copyright (C) 2004 - 2011 Philip Aston
2   // All rights reserved.
3   //
4   // This file is part of The Grinder software distribution. Refer to
5   // the file LICENSE which is part of The Grinder distribution for
6   // licensing details. The Grinder distribution is available on the
7   // Internet at http://grinder.sourceforge.net/
8   //
9   // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12  // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
13  // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
14  // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
15  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17  // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
18  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
19  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
20  // OF THE POSSIBILITY OF SUCH DAMAGE.
21  
22  package net.grinder.console.editor;
23  
24  import static org.junit.Assert.assertEquals;
25  import static org.junit.Assert.assertFalse;
26  import static org.junit.Assert.assertNotNull;
27  import static org.junit.Assert.assertNotSame;
28  import static org.junit.Assert.assertNull;
29  import static org.junit.Assert.assertSame;
30  import static org.junit.Assert.assertTrue;
31  import static org.junit.Assert.fail;
32  
33  import java.io.File;
34  import java.io.FileWriter;
35  import java.io.IOException;
36  import java.util.Arrays;
37  
38  import net.grinder.common.GrinderProperties;
39  import net.grinder.console.common.DisplayMessageConsoleException;
40  import net.grinder.console.common.Resources;
41  import net.grinder.console.common.ResourcesImplementation;
42  import net.grinder.console.distribution.AgentCacheState;
43  import net.grinder.console.distribution.FileChangeWatcher;
44  import net.grinder.console.editor.EditorModel.Listener;
45  import net.grinder.console.editor.StringTextSource.Factory;
46  import net.grinder.testutility.AbstractJUnit4FileTestCase;
47  import net.grinder.testutility.CallData;
48  import net.grinder.testutility.DelegatingStubFactory;
49  import net.grinder.testutility.RandomStubFactory;
50  
51  import org.junit.Test;
52  
53  
54  /**
55   * Unit test for {@link EditorModel}.
56   *
57   * @author Philip Aston
58   */
59  public class TestEditorModel extends AbstractJUnit4FileTestCase {
60  
61    private static final Resources s_resources =
62        new ResourcesImplementation(
63          "net.grinder.console.common.resources.Console");
64  
65    private final RandomStubFactory<AgentCacheState>
66      m_agentCacheStateStubFactory =
67        RandomStubFactory.create(AgentCacheState.class);
68    private final AgentCacheState m_agentCacheState =
69      m_agentCacheStateStubFactory.getStub();
70  
71    private final RandomStubFactory<FileChangeWatcher>
72      m_fileChangeWatcherStubFactory =
73        RandomStubFactory.create(FileChangeWatcher.class);
74    private final FileChangeWatcher m_fileChangeWatcher =
75      m_fileChangeWatcherStubFactory.getStub();
76  
77    @Test public void testConstruction() throws Exception {
78      final StringTextSource.Factory stringTextSourceFactory =
79        new StringTextSource.Factory();
80  
81      final DelegatingStubFactory<Factory> textSourceFactoryStubFactory =
82        DelegatingStubFactory.create(stringTextSourceFactory);
83      final EditorModel editorModel =
84        new EditorModel(s_resources,
85                        textSourceFactoryStubFactory.getStub(),
86                        m_agentCacheState,
87                        m_fileChangeWatcher);
88  
89      textSourceFactoryStubFactory.assertNoMoreCalls();
90      assertNull(editorModel.getSelectedBuffer());
91      assertEquals(0, editorModel.getBuffers().length);
92    }
93  
94    @Test public void testSelectBufferForFile() throws Exception {
95      final StringTextSource.Factory stringTextSourceFactory =
96        new StringTextSource.Factory();
97  
98      final DelegatingStubFactory<Factory> textSourceFactoryStubFactory =
99        DelegatingStubFactory.create(stringTextSourceFactory);
100     final EditorModel editorModel =
101       new EditorModel(s_resources,
102                       textSourceFactoryStubFactory.getStub(),
103                       m_agentCacheState,
104                       m_fileChangeWatcher);
105 
106     textSourceFactoryStubFactory.resetCallHistory();
107 
108     final File file1 = createFile("myfile.txt", "blah");
109     final File file2 = createFile("anotherFile.py", "Some stuff");
110 
111     final RandomStubFactory<Listener> listener1StubFactory =
112       RandomStubFactory.create(EditorModel.Listener.class);
113 
114     final RandomStubFactory<Listener> listener2StubFactory =
115       RandomStubFactory.create(EditorModel.Listener.class);
116 
117     editorModel.addListener(listener1StubFactory.getStub());
118     editorModel.addListener(listener2StubFactory.getStub());
119 
120     editorModel.selectBufferForFile(file1);
121 
122     assertNotNull(editorModel.getSelectedBuffer());
123     assertEquals(file1, editorModel.getSelectedBuffer().getFile());
124     textSourceFactoryStubFactory.assertSuccess("create");
125     textSourceFactoryStubFactory.assertNoMoreCalls();
126 
127     final CallData callData =
128       listener1StubFactory.assertSuccess("bufferAdded", Buffer.class);
129     final Buffer bufferForFile1 = (Buffer)callData.getParameters()[0];
130     assertSame(bufferForFile1, editorModel.getSelectedBuffer());
131     listener1StubFactory.assertSuccess("bufferStateChanged", bufferForFile1);
132     listener1StubFactory.assertNoMoreCalls();
133 
134     listener2StubFactory.assertSuccess("bufferAdded", bufferForFile1);
135     listener2StubFactory.assertSuccess("bufferStateChanged", bufferForFile1);
136     listener2StubFactory.assertNoMoreCalls();
137 
138     // Select same buffer is a no-op.
139     editorModel.selectBufferForFile(file1);
140 
141     assertSame(bufferForFile1, editorModel.getSelectedBuffer());
142     listener1StubFactory.assertNoMoreCalls();
143     listener2StubFactory.assertNoMoreCalls();
144 
145     editorModel.selectBufferForFile(file2);
146 
147     assertNotSame(bufferForFile1, editorModel.getSelectedBuffer());
148     textSourceFactoryStubFactory.assertSuccess("create");
149     textSourceFactoryStubFactory.assertNoMoreCalls();
150     listener1StubFactory.assertSuccess("bufferAdded", BufferImplementation.class);
151     listener1StubFactory.assertSuccess("bufferStateChanged", bufferForFile1);
152     listener1StubFactory.assertSuccess("bufferStateChanged", BufferImplementation.class);
153     listener1StubFactory.assertNoMoreCalls();
154     listener2StubFactory.assertSuccess("bufferAdded", BufferImplementation.class);
155     listener2StubFactory.assertSuccess("bufferStateChanged", bufferForFile1);
156     listener2StubFactory.assertSuccess("bufferStateChanged", BufferImplementation.class);
157     listener2StubFactory.assertNoMoreCalls();
158 
159     editorModel.selectBufferForFile(file1);
160 
161     textSourceFactoryStubFactory.assertNoMoreCalls();
162     assertSame(bufferForFile1, editorModel.getSelectedBuffer());
163     listener1StubFactory.assertSuccess("bufferStateChanged", BufferImplementation.class);
164     listener1StubFactory.assertSuccess("bufferStateChanged", bufferForFile1);
165     listener1StubFactory.assertNoMoreCalls();
166     listener2StubFactory.assertSuccess("bufferStateChanged", BufferImplementation.class);
167     listener2StubFactory.assertSuccess("bufferStateChanged", bufferForFile1);
168     listener2StubFactory.assertNoMoreCalls();
169 
170     final StringTextSource textSource1 =
171       (StringTextSource)bufferForFile1.getTextSource();
172 
173     textSource1.markDirty();
174     textSource1.markDirty();
175     textSource1.markDirty();
176     textSource1.markDirty();
177     listener1StubFactory.assertSuccess("bufferStateChanged", bufferForFile1);
178     listener1StubFactory.assertNoMoreCalls();
179     listener2StubFactory.assertSuccess("bufferStateChanged", bufferForFile1);
180     listener2StubFactory.assertNoMoreCalls();
181   }
182 
183   @Test public void testSelectNewBuffer() throws Exception {
184     final StringTextSource.Factory stringTextSourceFactory =
185       new StringTextSource.Factory();
186 
187     final DelegatingStubFactory<Factory> textSourceFactoryStubFactory =
188       DelegatingStubFactory.create(stringTextSourceFactory);
189 
190     final RandomStubFactory<Listener> listener1StubFactory =
191       RandomStubFactory.create(EditorModel.Listener.class);
192 
193     final EditorModel editorModel =
194       new EditorModel(s_resources,
195                       textSourceFactoryStubFactory.getStub(),
196                       m_agentCacheState,
197                       m_fileChangeWatcher);
198 
199     final Buffer defaultBuffer = editorModel.getSelectedBuffer();
200     assertNull(defaultBuffer);
201 
202     editorModel.addListener(listener1StubFactory.getStub());
203 
204     textSourceFactoryStubFactory.resetCallHistory();
205 
206     editorModel.selectNewBuffer();
207     textSourceFactoryStubFactory.assertSuccess("create");
208     textSourceFactoryStubFactory.assertNoMoreCalls();
209 
210     final Buffer buffer1 = editorModel.getSelectedBuffer();
211     assertNotSame(buffer1, defaultBuffer);
212 
213     listener1StubFactory.assertSuccess("bufferAdded", buffer1);
214     listener1StubFactory.assertSuccess("bufferStateChanged", buffer1);
215     listener1StubFactory.assertNoMoreCalls();
216 
217     editorModel.selectNewBuffer();
218 
219     final Buffer buffer2 = editorModel.getSelectedBuffer();
220     assertNotSame(buffer2, buffer1);
221 
222     listener1StubFactory.assertSuccess("bufferAdded", buffer2);
223     listener1StubFactory.assertSuccess("bufferStateChanged", buffer1);
224     listener1StubFactory.assertSuccess("bufferStateChanged", buffer2);
225     listener1StubFactory.assertNoMoreCalls();
226   }
227 
228   private File createFile(String name, String text) throws Exception {
229     final File file = new File(getDirectory(), name);
230     final FileWriter out = new FileWriter(file);
231     out.write(text);
232     out.close();
233 
234     return file;
235   }
236 
237   @Test public void testIsBoringFile() throws Exception {
238     final EditorModel editorModel =
239       new EditorModel(s_resources,
240                       new StringTextSource.Factory(),
241                       m_agentCacheState,
242                       m_fileChangeWatcher);
243 
244     final File[] boring = {
245       new File("some.class"),
246       new File("~temporary"),
247       new File("#BLAH BLAH"),
248       new File("furble.exe"),
249       new File("PIC.GIF"),
250       new File("dfadhklfda.Jpeg"),
251       new File("dfadhklfda.jpg"),
252       new File("dfadhklfda.tiff"),
253     };
254 
255     for (int i = 0; i < boring.length; ++i) {
256       assertTrue("Is boring: " + boring[i],
257                  editorModel.isBoringFile(boring[i]));
258     }
259 
260     final File[] notBoring = {
261       null,
262       new File("Script.Py"),
263       new File("some.java"),
264       new File("my.properties"),
265       new File("README"),
266       new File("info.text"),
267     };
268 
269     for (int i = 0; i < notBoring.length; ++i) {
270       assertTrue("Isn't boring: " + notBoring[i],
271                  !editorModel.isBoringFile(notBoring[i]));
272     }
273   }
274 
275   @Test public void testIsScriptFile() throws Exception {
276     final EditorModel editorModel =
277       new EditorModel(s_resources,
278                       new StringTextSource.Factory(),
279                       m_agentCacheState,
280                       m_fileChangeWatcher);
281 
282     final File[] script = {
283       new File("my file.py"),
284       new File(".blah.py"),
285       new File("python.PY"),
286       new File("~python.py"),
287       new File("clojure.clj"),
288       new File(".clj"),
289     };
290 
291     for (int i = 0; i < script.length; ++i) {
292       assertTrue("Is script: " + script[i],
293                  editorModel.isScriptFile(script[i]));
294     }
295 
296     final File[] notScript = {
297       null,
298       new File("script.python"),
299       new File("script.py "),
300       new File("foo.bah"),
301       new File("x.text"),
302     };
303 
304     for (int i = 0; i < notScript.length; ++i) {
305       assertTrue("Isn't script: " + notScript[i],
306                  !editorModel.isScriptFile(notScript[i]));
307     }
308   }
309 
310   @Test public void testIsPropertiesFile() throws Exception {
311     final EditorModel editorModel =
312       new EditorModel(s_resources,
313                       new StringTextSource.Factory(),
314                       m_agentCacheState,
315                       m_fileChangeWatcher);
316 
317     final File[] properties = {
318       new File("my file.properties"),
319       new File(".blah.properties"),
320       new File("python.PROPERTIES"),
321       new File("~python.properties"),
322     };
323 
324     for (int i = 0; i < properties.length; ++i) {
325       assertTrue("Is properties: " + properties[i],
326                  editorModel.isPropertiesFile(properties[i]));
327     }
328 
329     final File[] notProperties = {
330       null,
331       new File("script.props"),
332       new File("script.properties "),
333       new File("foo.bah"),
334       new File("x.text"),
335     };
336 
337     for (int i = 0; i < notProperties.length; ++i) {
338       assertTrue("Isn't properties: " + notProperties[i],
339                  !editorModel.isPropertiesFile(notProperties[i]));
340     }
341   }
342 
343   @Test public void testCloseBufferAndIsABufferDirty() throws Exception {
344     final EditorModel editorModel =
345       new EditorModel(s_resources,
346                       new StringTextSource.Factory(),
347                       m_agentCacheState,
348                       m_fileChangeWatcher);
349 
350     final RandomStubFactory<Listener> listenerStubFactory =
351       RandomStubFactory.create(EditorModel.Listener.class);
352 
353     final File file1 = createFile("myfile.txt", "blah");
354     final File file2 = createFile("another.py", "blah");
355 
356     editorModel.selectBufferForFile(file1);
357     final Buffer buffer1 = editorModel.getSelectedBuffer();
358 
359     editorModel.selectBufferForFile(file2);
360     final Buffer buffer2 = editorModel.getSelectedBuffer();
361 
362     editorModel.selectBufferForFile(createFile("blah", "blah"));
363     final Buffer buffer3 = editorModel.getSelectedBuffer();
364 
365     assertEquals(3, editorModel.getBuffers().length);
366 
367     assertTrue(!editorModel.isABufferDirty());
368 
369     editorModel.addListener(listenerStubFactory.getStub());
370 
371     editorModel.closeBuffer(buffer3);
372 
373     listenerStubFactory.assertSuccess("bufferStateChanged", buffer3);
374     listenerStubFactory.assertSuccess("bufferStateChanged", buffer2);
375     listenerStubFactory.assertSuccess("bufferRemoved", buffer3);
376     listenerStubFactory.assertNoMoreCalls();
377 
378     assertEquals(2, editorModel.getBuffers().length);
379 
380     assertEquals(buffer2, editorModel.getSelectedBuffer());
381 
382     assertTrue(!editorModel.isABufferDirty());
383 
384     ((StringTextSource)buffer1.getTextSource()).markDirty();
385 
386     assertTrue(editorModel.isABufferDirty());
387     listenerStubFactory.assertSuccess("bufferStateChanged", buffer1);
388     listenerStubFactory.assertNoMoreCalls();
389 
390     editorModel.closeBuffer(buffer1);
391 
392     assertTrue(!editorModel.isABufferDirty());
393     listenerStubFactory.assertSuccess("bufferRemoved", buffer1);
394     listenerStubFactory.assertNoMoreCalls();
395 
396     editorModel.closeBuffer(buffer1);
397     editorModel.closeBuffer(buffer3);
398     listenerStubFactory.assertNoMoreCalls();
399 
400     editorModel.closeBuffer(buffer2);
401     assertEquals(0, editorModel.getBuffers().length);
402 
403     assertTrue(!editorModel.isABufferDirty());
404 
405     listenerStubFactory.assertSuccess("bufferStateChanged", buffer2);
406     listenerStubFactory.assertSuccess("bufferRemoved", buffer2);
407     listenerStubFactory.assertNoMoreCalls();
408   }
409 
410   @Test public void testSaveBufferAs() throws Exception {
411     final StringTextSource.Factory stringTextSourceFactory =
412       new StringTextSource.Factory();
413 
414     final EditorModel editorModel = new EditorModel(s_resources,
415                                                     stringTextSourceFactory,
416                                                     m_agentCacheState,
417                                                     m_fileChangeWatcher);
418 
419     final RandomStubFactory<Listener> listenerStubFactory =
420       RandomStubFactory.create(EditorModel.Listener.class);
421 
422     editorModel.selectNewBuffer();
423     final Buffer buffer = editorModel.getSelectedBuffer();
424     stringTextSourceFactory.getLast().setText("Some text");
425 
426     final File file1 = new File(getDirectory(), "a file");
427     final File file2 = new File(getDirectory(), "another  file");
428 
429     editorModel.addListener(listenerStubFactory.getStub());
430 
431     buffer.save(file1);
432 
433     // Buffer changed because it is associated with a new file.
434     listenerStubFactory.assertSuccess("bufferStateChanged", buffer);
435     listenerStubFactory.assertNoMoreCalls();
436     m_agentCacheStateStubFactory.assertSuccess("setNewFileTime",
437                                                new Long(file1.lastModified()));
438     m_agentCacheStateStubFactory.assertNoMoreCalls();
439 
440     buffer.save(file1);
441     listenerStubFactory.assertNoMoreCalls();
442     m_agentCacheStateStubFactory.assertSuccess("setNewFileTime",
443                                                new Long(file1.lastModified()));
444     m_agentCacheStateStubFactory.assertNoMoreCalls();
445 
446     assertEquals(buffer, editorModel.getBufferForFile(file1));
447 
448     buffer.save(file2);
449 
450     // Buffer changed because it is associated with a new file.
451     listenerStubFactory.assertSuccess("bufferStateChanged", buffer);
452     listenerStubFactory.assertNoMoreCalls();
453     m_agentCacheStateStubFactory.assertSuccess("setNewFileTime",
454                                                new Long(file2.lastModified()));
455     m_agentCacheStateStubFactory.assertNoMoreCalls();
456 
457     assertNull(editorModel.getBufferForFile(file1));
458     assertEquals(buffer, editorModel.getBufferForFile(file2));
459   }
460 
461   @Test public void testGetAndSelectProperties() throws Exception {
462     final EditorModel editorModel =
463       new EditorModel(s_resources,
464                       new StringTextSource.Factory(),
465                       m_agentCacheState,
466                       m_fileChangeWatcher);
467 
468     assertNull(editorModel.getSelectedPropertiesFile());
469 
470     final File script = new File(getDirectory(), "lah");
471 
472     final File f1 = new File(".");
473     editorModel.setSelectedPropertiesFile(f1);
474     assertSame(f1, editorModel.getSelectedPropertiesFile());
475     editorModel.setSelectedPropertiesFile(null);
476     assertFalse(editorModel.isSelectedScript(script));
477     assertNull(editorModel.getSelectedPropertiesFile());
478     assertFalse(editorModel.isSelectedScript(script));
479 
480     final File f2 = new File(getDirectory(), "foo.properties");
481     editorModel.setSelectedPropertiesFile(f2);
482     assertFalse(editorModel.isSelectedScript(script));
483     final File defaultScript =
484       new File(getDirectory(), GrinderProperties.DEFAULT_SCRIPT.getPath());
485     assertTrue(editorModel.isSelectedScript(defaultScript));
486 
487     final GrinderProperties properties = new GrinderProperties(f2);
488     properties.setFile("grinder.script", script);
489     properties.save();
490     assertFalse(editorModel.isSelectedScript(script));
491     editorModel.setSelectedPropertiesFile(f2);
492     assertTrue(editorModel.isSelectedScript(script));
493     assertFalse(editorModel.isSelectedScript(defaultScript));
494 
495     // Again with relative path.
496     editorModel.setSelectedPropertiesFile(f1);
497     assertFalse(editorModel.isSelectedScript(script));
498     properties.setFile("grinder.script", new File(script.getName()));
499     properties.save();
500     assertFalse(editorModel.isSelectedScript(script));
501     editorModel.setSelectedPropertiesFile(f2);
502     assertTrue(editorModel.isSelectedScript(script));
503 
504     // Again with bogus path.
505     final char[] manyChars = new char[65536];
506     Arrays.fill(manyChars, 'x');
507     final File bogusFile = new File(new String(manyChars));
508     properties.setFile("grinder.script", bogusFile);
509     properties.save();
510     assertTrue(editorModel.isSelectedScript(script));
511     editorModel.setSelectedPropertiesFile(f2);
512     assertFalse(editorModel.isSelectedScript(bogusFile));
513     assertFalse(editorModel.isSelectedScript(script));
514   }
515 
516   @Test public void testAbstractListener() throws Exception {
517     final EditorModel.Listener listener = new EditorModel.AbstractListener() {};
518 
519     listener.bufferAdded(null);
520     listener.bufferNotUpToDate(null);
521     listener.bufferRemoved(null);
522     listener.bufferStateChanged(null);
523   }
524 
525   @Test public void testChangedFilesMonitoring() throws Exception {
526     final EditorModel editorModel =
527       new EditorModel(s_resources,
528                       new StringTextSource.Factory(),
529                       m_agentCacheState,
530                       m_fileChangeWatcher);
531 
532     final CallData addFileChangedListenerCallData =
533       m_fileChangeWatcherStubFactory.assertSuccess(
534         "addFileChangedListener",
535         FileChangeWatcher.FileChangedListener.class);
536 
537     final FileChangeWatcher.FileChangedListener fileChangedListener =
538       (FileChangeWatcher.FileChangedListener)
539       addFileChangedListenerCallData.getParameters()[0];
540 
541     final RandomStubFactory<Listener> editorModelListenerStubFactory =
542       RandomStubFactory.create(EditorModel.Listener.class);
543     editorModel.addListener(editorModelListenerStubFactory.getStub());
544 
545     final File f1 = new File(getDirectory(), "test file");
546     assertTrue(f1.createNewFile());
547     final Buffer buffer = editorModel.selectBufferForFile(f1);
548     assertTrue(buffer.isUpToDate());
549     editorModelListenerStubFactory.assertSuccess("bufferAdded", buffer);
550     editorModelListenerStubFactory.assertSuccess("bufferStateChanged", buffer);
551     editorModelListenerStubFactory.assertNoMoreCalls();
552 
553     assertTrue(f1.setLastModified(System.currentTimeMillis() + 1000));
554     assertFalse(buffer.isUpToDate());
555 
556     editorModelListenerStubFactory.assertNoMoreCalls();
557 
558     fileChangedListener.filesChanged(new File[] { getDirectory(), f1, });
559 
560     editorModelListenerStubFactory.assertSuccess("bufferNotUpToDate", buffer);
561     editorModelListenerStubFactory.assertNoMoreCalls();
562 
563     // Selecting a modified buffer should also fire bufferNotUpToDate.
564     assertTrue(f1.setLastModified(System.currentTimeMillis() + 2000));
565     editorModel.selectBufferForFile(f1);
566     editorModelListenerStubFactory.assertSuccess("bufferNotUpToDate", buffer);
567     editorModelListenerStubFactory.assertNoMoreCalls();
568   }
569 
570   @Test public void testOpenWithExternalEditor() throws Exception {
571     final EditorModel editorModel =
572       new EditorModel(s_resources,
573                       new StringTextSource.Factory(),
574                       m_agentCacheState,
575                       m_fileChangeWatcher);
576 
577     try {
578       editorModel.openWithExternalEditor(null);
579       fail("Expected DisplayMessageConsoleException");
580     }
581     catch (DisplayMessageConsoleException e) {
582       assertNull(e.getCause());
583     }
584 
585     editorModel.setExternalEditor(new File("not a command"), "bah");
586 
587     try {
588       editorModel.openWithExternalEditor(new File("foo"));
589       fail("Expected DisplayMessageConsoleException");
590     }
591     catch (DisplayMessageConsoleException e) {
592       assertTrue(e.getCause() instanceof IOException);
593     }
594 
595     editorModel.setExternalEditor(null, "bah");
596 
597     try {
598       editorModel.openWithExternalEditor(new File("foo"));
599       fail("Expected DisplayMessageConsoleException");
600     }
601     catch (DisplayMessageConsoleException e) {
602       assertNull(e.getCause());
603     }
604   }
605 }