001: /*BEGIN_COPYRIGHT_BLOCK
002: *
003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are met:
008: * * Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.
010: * * Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014: * names of its contributors may be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: *
029: * This software is Open Source Initiative approved Open Source Software.
030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
031: *
032: * This file is part of DrJava. Download the current version of this project
033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034: *
035: * END_COPYRIGHT_BLOCK*/
036:
037: package edu.rice.cs.drjava.ui;
038:
039: import java.io.File;
040: import java.awt.event.InputEvent;
041: import java.awt.event.KeyEvent;
042:
043: import edu.rice.cs.drjava.DrJavaTestCase;
044: import edu.rice.cs.drjava.config.FileOption;
045: import edu.rice.cs.drjava.model.GlobalModel;
046: import edu.rice.cs.drjava.model.repl.*;
047: import edu.rice.cs.drjava.model.repl.DummyInteractionsListener;
048: import edu.rice.cs.drjava.model.repl.InteractionsDJDocument;
049: import edu.rice.cs.drjava.model.repl.InteractionsDocument;
050: import edu.rice.cs.drjava.model.repl.InteractionsDocumentTest.TestBeep;
051: import edu.rice.cs.drjava.model.repl.InteractionsModel;
052: import edu.rice.cs.drjava.model.repl.InteractionsModelTest.TestInteractionsModel;
053: import edu.rice.cs.util.swing.Utilities;
054: import edu.rice.cs.util.text.EditDocumentException;
055: import edu.rice.cs.util.CompletionMonitor;
056: import java.util.Date;
057:
058: /** Test functions of InteractionsPane.
059: * @version $Id: InteractionsPaneTest.java 4255 2007-08-28 19:17:37Z mgricken $
060: */
061: public final class InteractionsPaneTest extends DrJavaTestCase {
062:
063: private static final char UNDEFINED = KeyEvent.CHAR_UNDEFINED;
064: private static final int PRESSED = KeyEvent.KEY_PRESSED;
065: private static final int RELEASED = KeyEvent.KEY_RELEASED;
066: private static final int SHIFT = InputEvent.SHIFT_MASK;
067: private static final int TYPED = KeyEvent.KEY_TYPED;
068: private static final int VK_UNDEF = KeyEvent.VK_UNDEFINED;
069:
070: protected volatile InteractionsDJDocument _adapter;
071: protected volatile InteractionsModel _model;
072: protected volatile InteractionsDocument _doc;
073: protected volatile InteractionsPane _pane;
074: protected volatile InteractionsController _controller;
075:
076: /** Setup method for each JUnit test case. */
077: public void setUp() throws Exception {
078: super .setUp();
079: _adapter = new InteractionsDJDocument();
080: _model = new TestInteractionsModel(_adapter);
081: _doc = _model.getDocument();
082: _pane = new InteractionsPane(_adapter) {
083: public int getPromptPos() {
084: return _model.getDocument().getPromptPos();
085: }
086: };
087: // Make tests silent
088: _pane.setBeep(new TestBeep());
089: _controller = new InteractionsController(_model, _adapter,
090: _pane);
091: _controller.setCachedCaretPos(_pane.getCaretPosition());
092: _controller.setCachedPromptPos(_doc.getPromptPos());
093: // System.err.println("_controller = " + _controller);
094: }
095:
096: public void tearDown() throws Exception {
097: // _controller = null;
098: // _doc = null;
099: // _model = null;
100: // _pane = null;
101: // _adapter = null;
102: super .tearDown();
103: }
104:
105: /** Tests that this.setUp() puts the caret in the correct position. */
106: public void testInitialPosition() {
107: assertEquals("Initial caret not in the correct position.",
108: _pane.getCaretPosition(), _doc.getPromptPos());
109: }
110:
111: /** Tests that moving the caret left when it's already at the prompt will cycle it to the end of the line. */
112: public void testCaretMovementCyclesWhenAtPrompt()
113: throws EditDocumentException {
114: _doc.append("test text", InteractionsDocument.DEFAULT_STYLE);
115: Utilities.invokeAndWait(new Runnable() {
116: public void run() {
117: _controller.moveToPrompt();
118: _controller.moveLeftAction.actionPerformed(null);
119: }
120: });
121: assertEquals(
122: "Caret was not cycled when moved left at the prompt.",
123: _doc.getLength(), _pane.getCaretPosition());
124: }
125:
126: /** Tests that moving the caret right when it's already at the end will cycle it to the prompt. */
127: public void testCaretMovementCyclesWhenAtEnd()
128: throws EditDocumentException {
129: _doc.append("test text", InteractionsDocument.DEFAULT_STYLE);
130: Utilities.invokeAndWait(new Runnable() {
131: public void run() {
132: _controller.moveToEnd();
133: _controller.moveRightAction.actionPerformed(null);
134: }
135: });
136: assertEquals(
137: "Caret was not cycled when moved right at the end.",
138: _doc.getPromptPos(), _pane.getCaretPosition());
139: }
140:
141: /** Tests that moving the caret left when it's before the prompt will cycle it to the prompt. */
142: public void testLeftBeforePromptMovesToPrompt() {
143: Utilities.invokeAndWait(new Runnable() {
144: public void run() {
145: _pane.setCaretPosition(1);
146: _controller.moveLeftAction.actionPerformed(null);
147: }
148: });
149: assertEquals(
150: "Left arrow doesn't move to prompt when caret is before prompt.",
151: _doc.getPromptPos(), _pane.getCaretPosition());
152: }
153:
154: /** Tests that moving the caret right when it's before the prompt will cycle it to the end of the document. */
155: public void testRightBeforePromptMovesToEnd() {
156: Utilities.invokeAndWait(new Runnable() {
157: public void run() {
158: _pane.setCaretPosition(1);
159: _controller.moveRightAction.actionPerformed(null);
160: }
161: });
162: assertEquals(
163: "Right arrow doesn't move to end when caret is before prompt.",
164: _doc.getLength(), _pane.getCaretPosition());
165: }
166:
167: /** Tests that moving the caret up (recalling the previous command from history) will move the caret to the end
168: * of the document.
169: */
170: public void testHistoryRecallPrevMovesToEnd() {
171: Utilities.invokeAndWait(new Runnable() {
172: public void run() {
173: _pane.setCaretPosition(1);
174: _controller.historyPrevAction.actionPerformed(null);
175: }
176: });
177: assertEquals("Caret not moved to end on up arrow.", _doc
178: .getLength(), _pane.getCaretPosition());
179: }
180:
181: /** Tests that moving the caret down (recalling the next command from history) will move the caret to the end of
182: * the document.
183: */
184: public void testHistoryRecallNextMovesToEnd() {
185: Utilities.invokeAndWait(new Runnable() {
186: public void run() {
187: _pane.setCaretPosition(1);
188: _controller.historyNextAction.actionPerformed(null);
189: }
190: });
191: assertEquals("Caret not moved to end on down arrow.", _doc
192: .getLength(), _pane.getCaretPosition());
193: }
194:
195: public void testCaretStaysAtEndDuringInteraction()
196: throws EditDocumentException {
197: // System.err.println("start caret pos = " + _pane.getCaretPosition());
198: // System.err.println("start prompt pos = " + _doc.getPromptPos());
199: _doc.setInProgress(true);
200: // System.err.println(_pane.getCaretPosition());
201: _doc.append("simulated output",
202: InteractionsDocument.DEFAULT_STYLE);
203: Utilities.clearEventQueue();
204: _doc.setInProgress(false);
205: // System.err.println("caret pos = " + _pane.getCaretPosition());
206: // System.err.println("prompt pos = " + _doc.getPromptPos());
207: // System.err.println("Document = |" + _doc.getDocText(0, _doc.getLength()) + "|");
208: assertEquals(
209: "Caret is at the end after output while in progress.",
210: _doc.getLength(), _pane.getCaretPosition());
211: }
212:
213: /** Tests that the caret catches up to the prompt if it is before it and output is displayed. */
214: public void testCaretMovesUpToPromptAfterInsert()
215: throws EditDocumentException {
216: _doc.append("typed text", InteractionsDocument.DEFAULT_STYLE);
217: Utilities.invokeAndWait(new Runnable() {
218: public void run() {
219: _pane.setCaretPosition(1);
220: }
221: });
222: _controller.setCachedCaretPos(1);
223: _doc.insertBeforeLastPrompt("simulated output",
224: InteractionsDocument.DEFAULT_STYLE);
225: Utilities.clearEventQueue();
226: assertEquals("Caret is at the prompt after output inserted.",
227: _doc.getPromptPos(), _pane.getCaretPosition());
228:
229: _doc.insertPrompt();
230: Utilities.invokeAndWait(new Runnable() {
231: public void run() {
232: _pane.setCaretPosition(1);
233: }
234: });
235: _doc.insertBeforeLastPrompt("simulated output",
236: InteractionsDocument.DEFAULT_STYLE);
237: Utilities.clearEventQueue();
238: assertEquals("Caret is at the end after output inserted.", _doc
239: .getPromptPos(), _pane.getCaretPosition());
240: }
241:
242: /** Tests that the caret is moved properly when the current interaction is cleared. */
243: public void testClearCurrentInteraction()
244: throws EditDocumentException {
245: _doc.append("typed text", InteractionsDocument.DEFAULT_STYLE);
246: Utilities.invokeAndWait(new Runnable() {
247: public void run() {
248: _controller.moveToEnd();
249: }
250: });
251:
252: _doc.clearCurrentInteraction();
253: Utilities.clearEventQueue();
254: assertEquals("Caret is at the prompt after output cleared.",
255: _doc.getPromptPos(), _pane.getCaretPosition());
256: assertEquals("Prompt is at the end after output cleared.", _doc
257: .getLength(), _doc.getPromptPos());
258: }
259:
260: /** Tests that the InteractionsPane cannot be edited before the prompt. */
261: public void testCannotEditBeforePrompt()
262: throws EditDocumentException {
263: _doc.acquireWriteLock();
264: int origLength = 0;
265: try {
266: origLength = _doc.getLength();
267: _doc.insertText(1, "typed text",
268: InteractionsDocument.DEFAULT_STYLE);
269: } finally {
270: _doc.releaseWriteLock();
271: }
272: assertEquals("Document should not have changed.", origLength,
273: _doc.getLength());
274: }
275:
276: /** Tests that the caret is put in the correct position after an insert. */
277: public void testCaretUpdatedOnInsert() throws EditDocumentException {
278: Utilities.invokeAndWait(new Runnable() {
279: public void run() {
280:
281: // Type 'T'
282: _pane.processKeyEvent(new KeyEvent(_pane, PRESSED,
283: (new Date()).getTime(), SHIFT, KeyEvent.VK_T,
284: UNDEFINED));
285: _pane.processKeyEvent(new KeyEvent(_pane, TYPED,
286: (new Date()).getTime(), 0, VK_UNDEF, 'T'));
287: _pane.processKeyEvent(new KeyEvent(_pane, RELEASED,
288: (new Date()).getTime(), SHIFT, KeyEvent.VK_T,
289: UNDEFINED));
290:
291: // Type 'Y'
292: _pane.processKeyEvent(new KeyEvent(_pane, PRESSED,
293: (new Date()).getTime(), SHIFT, KeyEvent.VK_Y,
294: UNDEFINED));
295: _pane.processKeyEvent(new KeyEvent(_pane, TYPED,
296: (new Date()).getTime(), 0, VK_UNDEF, 'Y'));
297: _pane.processKeyEvent(new KeyEvent(_pane, RELEASED,
298: (new Date()).getTime(), SHIFT, KeyEvent.VK_Y,
299: UNDEFINED));
300:
301: // Type 'P'
302: _pane.processKeyEvent(new KeyEvent(_pane, PRESSED,
303: (new Date()).getTime(), SHIFT, KeyEvent.VK_P,
304: UNDEFINED));
305: _pane.processKeyEvent(new KeyEvent(_pane, TYPED,
306: (new Date()).getTime(), 0, VK_UNDEF, 'P'));
307: _pane.processKeyEvent(new KeyEvent(_pane, RELEASED,
308: (new Date()).getTime(), SHIFT, KeyEvent.VK_P,
309: UNDEFINED));
310:
311: // Type 'E'
312: _pane.processKeyEvent(new KeyEvent(_pane, PRESSED,
313: (new Date()).getTime(), SHIFT, KeyEvent.VK_E,
314: UNDEFINED));
315: _pane.processKeyEvent(new KeyEvent(_pane, TYPED,
316: (new Date()).getTime(), 0, VK_UNDEF, 'E'));
317: _pane.processKeyEvent(new KeyEvent(_pane, RELEASED,
318: (new Date()).getTime(), SHIFT, KeyEvent.VK_E,
319: UNDEFINED));
320:
321: // Type 'D'
322: _pane.processKeyEvent(new KeyEvent(_pane, PRESSED,
323: (new Date()).getTime(), SHIFT, KeyEvent.VK_D,
324: UNDEFINED));
325: _pane.processKeyEvent(new KeyEvent(_pane, TYPED,
326: (new Date()).getTime(), 0, VK_UNDEF, 'D'));
327: _pane.processKeyEvent(new KeyEvent(_pane, RELEASED,
328: (new Date()).getTime(), SHIFT, KeyEvent.VK_D,
329: UNDEFINED));
330: }
331: });
332: // System.err.println("Document = '" + _doc.getText() + "'");
333: Utilities.clearEventQueue();
334: Utilities.clearEventQueue();
335: assertEquals("caret should be at end of document", _doc
336: .getLength(), _pane.getCaretPosition());
337:
338: final int pos = _doc.getLength() - 5;
339: Utilities.invokeAndWait(new Runnable() {
340: public void run() {
341: _pane.setCaretPosition(pos);
342: }
343: });
344: _controller.setCachedCaretPos(pos);
345: // System.err.println("docLength = " + _doc.getLength() + " caretPos = " + _pane.getCaretPosition());
346:
347: // Insert text before the prompt
348: _doc.insertBeforeLastPrompt("aa",
349: InteractionsDocument.DEFAULT_STYLE);
350: Utilities.clearEventQueue();
351: // System.err.println("Document = '" + _doc.getText() + "'");
352: assertEquals("caret should be in correct position", pos + 2,
353: _pane.getCaretPosition());
354:
355: // Move caret to prompt and insert more text
356: Utilities.invokeAndWait(new Runnable() {
357: public void run() {
358: _pane.setCaretPosition(_doc.getPromptPos());
359: }
360: });
361: _doc.insertBeforeLastPrompt("b",
362: InteractionsDocument.DEFAULT_STYLE);
363: Utilities.clearEventQueue();
364: assertEquals("caret should be at prompt", _doc.getPromptPos(),
365: _pane.getCaretPosition());
366:
367: // Move caret before prompt and insert more text
368: Utilities.invokeAndWait(new Runnable() {
369: public void run() {
370: _pane.setCaretPosition(0);
371: }
372: });
373: _doc.insertBeforeLastPrompt("ccc",
374: InteractionsDocument.DEFAULT_STYLE);
375: Utilities.clearEventQueue();
376: assertEquals("caret should be at prompt", _doc.getPromptPos(),
377: _pane.getCaretPosition());
378:
379: // Move caret after prompt and insert more text
380: final int newPos = _doc.getPromptPos();
381: // simulate a keystroke by putting caret just *after* pos of insert
382: _pane.setCaretPosition(newPos + 1);
383: _controller.setCachedCaretPos(newPos + 1);
384: Utilities.invokeAndWait(new Runnable() {
385: public void run() {
386: // Type 'D'
387: _pane.processKeyEvent(new KeyEvent(_pane, PRESSED,
388: (new Date()).getTime(), SHIFT, KeyEvent.VK_D,
389: UNDEFINED));
390: _pane.processKeyEvent(new KeyEvent(_pane, TYPED,
391: (new Date()).getTime(), 0, VK_UNDEF, 'D'));
392: _pane.processKeyEvent(new KeyEvent(_pane, RELEASED,
393: (new Date()).getTime(), SHIFT, KeyEvent.VK_D,
394: UNDEFINED));
395: }
396: });
397: Utilities.clearEventQueue();
398: assertEquals("caret should be one char after the inserted D",
399: newPos + 2, _pane.getCaretPosition());
400: }
401:
402: public void testSystemIn() {
403: final Object bufLock = new Object();
404: final StringBuilder buf = new StringBuilder();
405:
406: final CompletionMonitor completionMonitor = new CompletionMonitor();
407:
408: _controller
409: .addConsoleStateListener(new InteractionsController.ConsoleStateListener() {
410: public void consoleInputStarted(
411: InteractionsController c) {
412: completionMonitor.set();
413: }
414:
415: public void consoleInputCompleted(String text,
416: InteractionsController c) {
417: // do not assert the text here since it won't be called from the testing thread.
418: // It is called on the following thread that calls getConsoleInput()
419: }
420: });
421:
422: new Thread("Testing System.in") {
423: public void run() {
424: synchronized (bufLock) {
425: String s = _controller.getInputListener()
426: .getConsoleInput();
427: buf.append(s);
428: }
429: }
430: }.start();
431:
432: // Wait for console input to begin
433: completionMonitor.waitOne();
434:
435: Utilities.invokeAndWait(new Runnable() {
436: public void run() {
437: _controller.insertConsoleText("test-text");
438: _controller.interruptConsoleInput();
439: }
440: });
441:
442: // Make sure the buffer 'buf' is updated
443: synchronized (bufLock) {
444: assertEquals("Should have returned the correct text.",
445: "test-text\n", buf.toString());
446: }
447: }
448:
449: // NOT USED
450: // /** Fields used in a closure in testPromptList */
451: // private volatile int _firstPrompt, _secondPrompt, _size;
452: // private volatile boolean _resetDone;
453: //
454: // public void testPromptListClearedOnReset() throws Exception {
455: // // Can't use the fields declared in setUp; we need a real InteractionsModel
456: // final MainFrame _mf = new MainFrame();
457: // final Object _resetLock = new Object();
458: //
459: // Utilities.clearEventQueue();
460: // GlobalModel gm = _mf.getModel();
461: // _controller = _mf.getInteractionsController();
462: // _model = gm.getInteractionsModel();
463: // _adapter = gm.getSwingInteractionsDocument();
464: // _doc = gm.getInteractionsDocument();
465: // _pane = _mf.getInteractionsPane();
466: //
467: // Utilities.invokeAndWait(new Runnable() { public void run() { _pane.resetPrompts(); } });
468: //
469: // Utilities.clearEventQueue();
470: //
471: //// System.err.println(_pane.getPromptList());
472: // assertEquals("PromptList before insert should contain 0 elements", 0, _pane.getPromptList().size());
473: //
474: // // Insert some text
475: // _doc.append("5", InteractionsDocument.NUMBER_RETURN_STYLE);
476: //
477: // Utilities.invokeAndWait(new Runnable() { public void run() { _pane.setCaretPosition(_doc.getLength()); } });
478: //// System.err.println(_pane.getPromptList());
479: //
480: // Utilities.clearEventQueue();
481: //
482: // assertEquals("PromptList after insert should contain 1 element", 1, _pane.getPromptList().size());
483: // assertEquals("First prompt should be saved as being at position",
484: // _model.getStartUpBanner().length() + InteractionsDocument.DEFAULT_PROMPT.length(),
485: // (int)_pane.getPromptList().get(0)); //needs cast to prevent ambiguity
486: //
487: // _doc.insertPrompt();
488: // Utilities.clearEventQueue();
489: //
490: // assertEquals("PromptList has length 2", 2, _pane.getPromptList().size());
491: //
492: // Utilities.invokeAndWait(new Runnable() {
493: // public void run() {
494: // _pane.setCaretPosition(_doc.getLength());
495: // _firstPrompt = (int) _pane.getPromptList().get(0); // cast prevents ambiguity
496: // _secondPrompt = (int) _pane.getPromptList().get(1); // cast prevents ambiguity
497: // }
498: // });
499: //
500: // assertEquals("PromptList after insertion of new prompt should contain 2 elements", 2, _pane.getPromptList().size());
501: // assertEquals("First prompt should be saved as being at position",
502: // _model.getStartUpBanner().length() + InteractionsDocument.DEFAULT_PROMPT.length(),
503: // _firstPrompt);
504: // assertEquals("Second prompt should be saved as being at position",
505: // _model.getStartUpBanner().length() + InteractionsDocument.DEFAULT_PROMPT.length() * 2 + 1,
506: // _secondPrompt);
507: //
508: // synchronized(_resetLock) { _resetDone = false; }
509: // _model.addListener(new DummyInteractionsListener() {
510: // public void interpreterReady(File wd) {
511: // synchronized(_resetLock) {
512: // _resetDone = true;
513: // _resetLock.notifyAll();
514: // }
515: // }});
516: //
517: //// System.err.println("Executing reset interpreter");
518: // _model.resetInterpreter(FileOption.NULL_FILE);
519: // Utilities.clearEventQueue();
520: //
521: // /* Wait until reset has finished. Reset is started just before interpreterReady notification. */
522: // synchronized(_resetLock) { while (! _resetDone) _resetLock.wait(); }
523: // Utilities.clearEventQueue();
524: //
525: // _doc.acquireWriteLock();
526: // try { // wait until the reset operation (which is queued ahead of us) has grabbed the WriteLock
527: // Utilities.invokeAndWait(new Runnable() { public void run() { _size = _pane.getPromptList().size(); } });
528: // }
529: // finally { _doc.releaseWriteLock(); }
530: //
531: // Utilities.clearEventQueue();
532: //// System.err.println("PromptList for pane " + _pane.hashCode() + " is " + _pane.getPromptList());
533: //
534: // assertEquals("PromptList after reset should contain one element", 1, _size);
535: // }
536:
537: }
|