0001: /*BEGIN_COPYRIGHT_BLOCK
0002: *
0003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
0004: * All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions are met:
0008: * * Redistributions of source code must retain the above copyright
0009: * notice, this list of conditions and the following disclaimer.
0010: * * Redistributions in binary form must reproduce the above copyright
0011: * notice, this list of conditions and the following disclaimer in the
0012: * documentation and/or other materials provided with the distribution.
0013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
0014: * names of its contributors may be used to endorse or promote products
0015: * derived from this software without specific prior written permission.
0016: *
0017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0028: *
0029: * This software is Open Source Initiative approved Open Source Software.
0030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
0031: *
0032: * This file is part of DrJava. Download the current version of this project
0033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
0034: *
0035: * END_COPYRIGHT_BLOCK*/
0036:
0037: package edu.rice.cs.drjava.ui;
0038:
0039: import java.awt.Component;
0040: import java.awt.event.*;
0041: import java.awt.datatransfer.Clipboard;
0042: import java.awt.datatransfer.DataFlavor;
0043: import java.awt.datatransfer.StringSelection;
0044: import java.awt.datatransfer.Transferable;
0045: import java.awt.datatransfer.UnsupportedFlavorException;
0046: import java.awt.Toolkit;
0047: import javax.swing.*;
0048: import javax.swing.text.*;
0049: import java.io.*;
0050: import java.util.List;
0051:
0052: import edu.rice.cs.drjava.model.*;
0053: import edu.rice.cs.drjava.model.repl.*;
0054: import edu.rice.cs.drjava.model.repl.InteractionsDocumentTest.TestBeep;
0055: import edu.rice.cs.drjava.DrJava;
0056: import edu.rice.cs.drjava.config.OptionConstants;
0057: import edu.rice.cs.plt.io.IOUtil;
0058: import edu.rice.cs.util.FileOpenSelector;
0059: import edu.rice.cs.util.*;
0060: import edu.rice.cs.util.text.*;
0061: import edu.rice.cs.util.swing.Utilities;
0062:
0063: /** Test functions of MainFrame.
0064: * @version $Id: MainFrameTest.java 4255 2007-08-28 19:17:37Z mgricken $
0065: */
0066: public final class MainFrameTest extends MultiThreadedTestCase {
0067:
0068: private volatile MainFrame _frame;
0069:
0070: /** A temporary directory */
0071: private volatile File _tempDir;
0072:
0073: /* Flag and lock for signalling when file has been opened and active document changed. */
0074: protected volatile boolean _openDone;
0075: protected final Object _openLock = new Object();
0076:
0077: /* Flag and lock for signalling when file has been closed. */
0078: protected volatile boolean _closeDone;
0079: protected final Object _closeLock = new Object();
0080:
0081: /* Flag and lock for signalling when compilation is done. */
0082: protected volatile boolean _compileDone;
0083: protected final Object _compileLock = new Object();
0084:
0085: private final static Log _log = new Log("MainFrameTest.txt", false);
0086:
0087: /** Setup method for each JUnit test case. */
0088: public void setUp() throws Exception {
0089: super .setUp();
0090: _log.log("super.setUp() for next test completed");
0091:
0092: _frame = new MainFrame();
0093: _log.log("new MainFrame() for next test completed");
0094: _frame.pack();
0095: _log.log("setUp complete for next test");
0096: }
0097:
0098: public void tearDown() throws Exception {
0099: super .tearDown();
0100: // Utilities.invokeAndWait(new Runnable() {
0101: // public void run() {
0102: _frame.dispose(); // disposes GUI elements of _frame
0103: _frame.getModel().dispose(); // explicitly kills the slave JVM
0104: _frame = null;
0105: // }
0106: // });
0107: //
0108:
0109: }
0110:
0111: JButton _but;
0112:
0113: /** Tests that the returned JButton of <code>createManualToolbarButton</code>:
0114: * 1. Is disabled upon return.
0115: * 2. Inherits the tooltip of the Action parameter <code>a</code>.
0116: */
0117: public void testCreateManualToolbarButton() {
0118: final Action a = new AbstractAction("Test Action") {
0119: public void actionPerformed(ActionEvent ae) {
0120: }
0121: };
0122:
0123: a.putValue(Action.SHORT_DESCRIPTION, "test tooltip");
0124: Utilities.invokeAndWait(new Runnable() {
0125: public void run() {
0126: _but = _frame._createManualToolbarButton(a);
0127: }
0128: });
0129:
0130: assertTrue("Returned JButton is enabled.", !_but.isEnabled());
0131: assertEquals("Tooltip text not set.", "test tooltip", _but
0132: .getToolTipText());
0133: _log.log("testCreateManualToobarButton completed");
0134: }
0135:
0136: /** Tests that the current location of a document is equal to the caret location after documents are switched. */
0137: public void testDocLocationAfterSwitch()
0138: throws BadLocationException {
0139: final DefinitionsPane pane = _frame.getCurrentDefPane();
0140: OpenDefinitionsDocument doc = pane.getOpenDefDocument();
0141: doc.insertString(0, "abcd", null);
0142: Utilities.invokeAndWait(new Runnable() {
0143: public void run() {
0144: pane.setCaretPosition(3);
0145: }
0146: });
0147: Utilities.clearEventQueue(); // Empty the event queue of any asynchronous tasks
0148:
0149: assertEquals("Location of old doc before switch", 3, doc
0150: .getCurrentLocation());
0151:
0152: // Create a new file
0153: SingleDisplayModel model = _frame.getModel();
0154: final OpenDefinitionsDocument oldDoc = doc;
0155: final OpenDefinitionsDocument newDoc = model.newFile();
0156:
0157: // Current pane should be new doc, pos 0
0158: DefinitionsPane curPane;
0159: OpenDefinitionsDocument curDoc;
0160: curPane = _frame.getCurrentDefPane();
0161: curDoc = curPane.getOpenDefDocument();//.getDocument();
0162: assertEquals("New curr DefPane's document", newDoc, curDoc);
0163: assertEquals("Location in new document", 0, newDoc
0164: .getCurrentLocation());
0165:
0166: // Switch back to old document
0167: model.setActiveNextDocument();
0168: assertEquals("Next active doc", oldDoc, model
0169: .getActiveDocument());
0170:
0171: // Current pane should be old doc, pos 3
0172: curPane = _frame.getCurrentDefPane();
0173: curDoc = curPane.getOpenDefDocument();//.getDocument();
0174: assertEquals("Current document is old document", oldDoc, curDoc);
0175: assertEquals("Location of old document", 3, curDoc
0176: .getCurrentLocation());
0177: _log.log("testDocLocationAfterSwitch completed");
0178: }
0179:
0180: private String _data;
0181: private String _newData;
0182:
0183: /** Tests that the clipboard is unmodified after a "clear line" action. */
0184: public void testClearLine() throws BadLocationException,
0185: UnsupportedFlavorException, IOException {
0186: // First, copy some data out of the main document.
0187: final DefinitionsPane pane = _frame.getCurrentDefPane();
0188: final OpenDefinitionsDocument doc = pane.getOpenDefDocument();
0189: final String clipString = "***Clipboard***";
0190: // _frame.setVisible(true);
0191:
0192: Utilities.invokeAndWait(new Runnable() {
0193: public void run() {
0194:
0195: try {
0196: doc.insertString(0, "abcdefg", null);
0197: pane.setCaretPosition(5);
0198:
0199: // ActionMap actionMap = _pane.getActionMap();
0200: // String selString = DefaultEditorKit.selectionEndLineAction;
0201: // actionMap.get(selString).actionPerformed(new ActionEvent(this, 0, "SelectionEndLine"));
0202: // _frame.cutAction.actionPerformed(new ActionEvent(this, 0, "Cut"));
0203:
0204: _frame.validate();
0205: // _frame.paint(_frame.getGraphics());
0206: // ActionMap actionMap = _pane.getActionMap();
0207: // String selString = DefaultEditorKit.selectionEndLineAction;
0208: // actionMap.get(selString).actionPerformed(new ActionEvent(this, 0, "SelectionEndLine"));
0209: // pane.setSelectionStart(2);
0210: // pane.setSelectionEnd(7);
0211:
0212: // Get a copy of the current clipboard.
0213: Clipboard clip = Toolkit.getDefaultToolkit()
0214: .getSystemClipboard();
0215: // Insert valid string in clipboars.
0216:
0217: clip.setContents(new StringSelection(clipString),
0218: _frame);
0219: Transferable contents = clip.getContents(_frame);
0220:
0221: // Trigger the Clear Line action from a new position.
0222: pane.setCaretPosition(2);
0223: _frame.validate();
0224: // _frame.paint(_frame.getGraphics());
0225:
0226: _frame._clearLineAction
0227: .actionPerformed(new ActionEvent(pane, 0,
0228: "Clear Line"));
0229: // _frame.paint(_frame.getGraphics());
0230: _frame.validate();
0231:
0232: // Verify that the clipboard contents are still the same.
0233: contents = clip.getContents(null);
0234: _data = (String) contents
0235: .getTransferData(DataFlavor.stringFlavor);
0236: } catch (Throwable t) {
0237: listenerFail(t.getMessage());
0238: }
0239: }
0240: });
0241: Utilities.clearEventQueue();
0242:
0243: assertEquals(
0244: "Clipboard contents should be unchanged after Clear Line.",
0245: clipString, _data);
0246:
0247: // Verify that the document text is what we expect.
0248: assertEquals(
0249: "Current line of text should be truncated by Clear Line.",
0250: "ab", doc.getText());
0251: _log.log("testClearLine completed");
0252: }
0253:
0254: /** Tests that the clipboard is modified after a "cut line" action.
0255: * NOTE: Commented out for commit because of failures, despite proper behavior in GUI.
0256: * This may not work unless ActionEvents are dropped in the event queue
0257: */
0258: public void testCutLine() throws BadLocationException {
0259: // First, copy some data out of the main document.
0260:
0261: final DefinitionsPane pane = _frame.getCurrentDefPane();
0262: final OpenDefinitionsDocument doc = pane.getOpenDefDocument();
0263: // _frame.setVisible(true);
0264: Utilities.invokeAndWait(new Runnable() {
0265: public void run() {
0266:
0267: try {
0268: doc.insertString(0, "abcdefg", null);
0269: pane.setCaretPosition(5);
0270: _frame.validate();
0271: // _frame.paint(_frame.getGraphics());
0272: // ActionMap actionMap = _pane.getActionMap();
0273: // String selString = DefaultEditorKit.selectionEndLineAction;
0274: // actionMap.get(selString).actionPerformed(new ActionEvent(pane, 0, "SelectionEndLine"));
0275: pane.setSelectionStart(2);
0276: pane.setSelectionEnd(7);
0277: _frame.validate();
0278: pane.cut();
0279: // _frame.cutAction.actionPerformed(new ActionEvent(pane, 0, "Cut"));
0280:
0281: // Get a copy of the current clipboard.
0282:
0283: // Trigger the Cut Line action from a new position.
0284: // _pane.setCaretPosition(2);
0285: _frame.validate();
0286: // _frame.paint(_frame.getGraphics());
0287:
0288: // _frame._cutLineAction.actionPerformed(new ActionEvent(this, 0, "Cut Line"));
0289: // _frame.dispatchEvent(new ActionEvent(this, 0, "Cut Line"));
0290:
0291: // Verify that the clipboard contents are what we expect.
0292: Clipboard clip = Toolkit.getDefaultToolkit()
0293: .getSystemClipboard();
0294: Transferable contents = clip.getContents(null);
0295: _data = (String) contents
0296: .getTransferData(DataFlavor.stringFlavor);
0297: } catch (Throwable t) {
0298: listenerFail(t.getMessage());
0299: }
0300: }
0301: });
0302: Utilities.clearEventQueue();
0303: assertEquals(
0304: "Clipboard contents should be changed after Cut Line.",
0305: "cdefg", _data);
0306:
0307: // Verify that the document text is what we expect.
0308: assertEquals(
0309: "Current line of text should be truncated by Cut Line.",
0310: "ab", doc.getText());
0311: _log.log("testCutLine completed");
0312: }
0313:
0314: /** Make sure that the InteractionsPane is displaying the correct InteractionsDocument. (SourceForge bug #681547)
0315: * Also make sure this document cannot be edited before the prompt.
0316: */
0317: public void testCorrectInteractionsDocument()
0318: throws EditDocumentException {
0319: InteractionsPane pane = _frame.getInteractionsPane();
0320: final SingleDisplayModel model = _frame.getModel();
0321: InteractionsDJDocument doc = model
0322: .getSwingInteractionsDocument();
0323:
0324: // Make the test silent
0325: Utilities.invokeAndWait(new Runnable() {
0326: public void run() {
0327: model.getInteractionsModel().getDocument().setBeep(
0328: new TestBeep());
0329: }
0330: });
0331: Utilities.clearEventQueue();
0332:
0333: // Test for strict == equality
0334: assertTrue("UI's int. doc. should equals Model's int. doc.",
0335: pane.getDocument() == doc);
0336:
0337: int origLength = doc.getLength();
0338: doc.insertText(1, "typed text",
0339: InteractionsDocument.DEFAULT_STYLE);
0340: Utilities.clearEventQueue();
0341: assertEquals("Document should not have changed.", origLength,
0342: doc.getLength());
0343: _log.log("testCorrectInteractionsDocument completed");
0344: }
0345:
0346: /** Tests that undoing/redoing a multi-line indent will restore the caret position. */
0347: public void testMultilineIndentAfterScroll()
0348: throws BadLocationException, InterruptedException {
0349: String text = "public class stuff {\n" + "private int _int;\n"
0350: + "private Bar _bar;\n" + "public void foo() {\n"
0351: + "_bar.baz(_int);\n" + "}\n" + "}\n";
0352:
0353: String indented = "public class stuff {\n"
0354: + " private int _int;\n" + " private Bar _bar;\n"
0355: + " public void foo() {\n" + " _bar.baz(_int);\n"
0356: + " }\n" + "}\n";
0357:
0358: final int newPos = 20;
0359:
0360: final DefinitionsPane pane = _frame.getCurrentDefPane();
0361: final OpenDefinitionsDocument doc = pane.getOpenDefDocument();
0362:
0363: DrJava.getConfig().setSetting(OptionConstants.INDENT_LEVEL,
0364: new Integer(2));
0365: doc.append(text, null);
0366: Utilities.invokeAndWait(new Runnable() {
0367: public void run() {
0368: pane.setCaretPosition(0);
0369: pane.endCompoundEdit();
0370: }
0371: });
0372:
0373: Utilities.clearEventQueue();
0374: assertEquals("Should have inserted correctly.", text, doc
0375: .getText());
0376:
0377: doc.acquireWriteLock();
0378:
0379: try {
0380: doc.indentLines(0, doc.getLength());
0381: } finally {
0382: doc.releaseWriteLock();
0383: }
0384:
0385: assertEquals("Should have indented.", indented, doc.getText());
0386:
0387: final int oldPos = pane.getCaretPosition();
0388: // System.err.println("Old position is: " + oldPos);
0389:
0390: Utilities.invokeAndWait(new Runnable() {
0391: public void run() {
0392: pane.setCaretPosition(newPos);
0393: // System.err.println("New position is: " + pane.getCaretPosition());
0394: }
0395: });
0396: Utilities.clearEventQueue();
0397: // Moving this statement to the event thread breaks "Undo should have restored ..." Why? Timing.
0398: // Inserting Thread.sleep(500) does the same thing
0399: doc.getUndoManager().undo();
0400:
0401: assertEquals("Should have undone.", text, doc.getText());
0402:
0403: int rePos = pane.getCaretPosition();
0404: // System.err.println("Restored position is: " + rePos);
0405: assertEquals("Undo should have restored caret position.",
0406: oldPos, rePos);
0407:
0408: Utilities.invokeAndWait(new Runnable() {
0409: public void run() {
0410: pane.setCaretPosition(newPos);
0411: doc.getUndoManager().redo();
0412: }
0413: });
0414: Utilities.clearEventQueue();
0415:
0416: assertEquals("redo", indented, doc.getText());
0417: assertEquals("redo restores caret position", oldPos, pane
0418: .getCaretPosition());
0419: _log.log("testMultilineIndentAfterScroll completed");
0420: }
0421:
0422: JScrollPane _pane1, _pane2;
0423: DefinitionsPane _defPane1, _defPane2;
0424:
0425: /** Ensure that a document's editable status is set appropriately throughout the compile process. Since the behavior
0426: * is interesting only when the model changes its active document, that's what this test looks most like.
0427: */
0428: public void testGlassPaneEditableState() {
0429: SingleDisplayModel model = _frame.getModel();
0430:
0431: final OpenDefinitionsDocument doc1 = model.newFile();
0432: final OpenDefinitionsDocument doc2 = model.newFile();
0433:
0434: // doc2 is now active
0435: Utilities.invokeAndWait(new Runnable() {
0436: public void run() {
0437:
0438: _pane1 = _frame._createDefScrollPane(doc1);
0439: _pane2 = _frame._createDefScrollPane(doc2);
0440:
0441: _defPane1 = (DefinitionsPane) _pane1.getViewport()
0442: .getView();
0443: _defPane2 = (DefinitionsPane) _pane2.getViewport()
0444: .getView();
0445:
0446: _frame._switchDefScrollPane();
0447: }
0448: });
0449:
0450: Utilities.clearEventQueue(); // Execute all pending asynchronous tasks;
0451:
0452: assertTrue("Start: defPane1", _defPane1.isEditable());
0453: assertTrue("Start: defPane2", _defPane2.isEditable());
0454:
0455: Utilities.invokeAndWait(new Runnable() {
0456: public void run() {
0457: _frame.hourglassOn();
0458: }
0459: });
0460: Utilities.clearEventQueue();
0461:
0462: assertTrue("Glass on: defPane1", _defPane1.isEditable());
0463: assertTrue("Glass on: defPane2", (!_defPane2.isEditable()));
0464: model.setActiveDocument(doc1);
0465:
0466: Utilities.invokeAndWait(new Runnable() {
0467: public void run() {
0468: _frame._switchDefScrollPane();
0469: }
0470: });
0471: Utilities.clearEventQueue();
0472:
0473: assertTrue("Doc Switch: defPane1", (!_defPane1.isEditable()));
0474: assertTrue("Doc Switch: defPane2", _defPane2.isEditable());
0475:
0476: Utilities.invokeAndWait(new Runnable() {
0477: public void run() {
0478: _frame.hourglassOff();
0479: }
0480: });
0481: Utilities.clearEventQueue();
0482:
0483: assertTrue("End: defPane1", _defPane1.isEditable());
0484: assertTrue("End: defPane2", _defPane2.isEditable());
0485: _log.log("testGlassPaneEditableState completed");
0486: }
0487:
0488: private KeyEvent makeFindKeyEvent(Component c, long when) {
0489: return new KeyEvent(c, KeyEvent.KEY_PRESSED, when,
0490: KeyEvent.CTRL_MASK, KeyEvent.VK_F, 'F');
0491: }
0492:
0493: /** Ensure that all key events are disabled when the glass pane is up. */
0494: public void testGlassPaneHidesKeyEvents() {
0495: SingleDisplayModel model = _frame.getModel();
0496:
0497: final OpenDefinitionsDocument doc1 = model.newFile();
0498: final OpenDefinitionsDocument doc2 = model.newFile();
0499:
0500: // doc2 is now active
0501: Utilities.invokeAndWait(new Runnable() {
0502: public void run() {
0503: _pane1 = _frame._createDefScrollPane(doc1);
0504: _pane2 = _frame._createDefScrollPane(doc2);
0505: _defPane1 = (DefinitionsPane) _pane1.getViewport()
0506: .getView();
0507: _defPane2 = (DefinitionsPane) _pane2.getViewport()
0508: .getView();
0509: _frame.validate();
0510: _frame.hourglassOn();
0511: _defPane1.processKeyEvent(makeFindKeyEvent(_defPane1,
0512: 70));
0513: _frame.validate();
0514: }
0515: });
0516: Utilities.clearEventQueue();
0517:
0518: assertTrue("the find replace dialog should not come up",
0519: !_frame.getFindReplaceDialog().isDisplayed());
0520: Utilities.invokeAndWait(new Runnable() {
0521: public void run() {
0522: _frame.getInteractionsPane().processKeyEvent(
0523: makeFindKeyEvent(_frame.getInteractionsPane(),
0524: 0));
0525: _frame.validate();
0526: }
0527: });
0528: Utilities.clearEventQueue();
0529:
0530: assertTrue("the find replace dialog should not come up",
0531: !_frame.getFindReplaceDialog().isDisplayed());
0532:
0533: Utilities.invokeAndWait(new Runnable() {
0534: public void run() {
0535: _frame.hourglassOff();
0536: }
0537: });
0538: _log.log("testGlassPaneHidesKeyEvents completed");
0539: }
0540:
0541: /** Tests that the save button does not set itself as enabled immediately after opening a file. */
0542: public void testSaveButtonEnabled() throws IOException {
0543: String user = System.getProperty("user.name");
0544: _tempDir = IOUtil.createAndMarkTempDirectory("DrJava-test-"
0545: + user, "");
0546: File forceOpenClass1_file = new File(_tempDir,
0547: "ForceOpenClass1.java");
0548: String forceOpenClass1_string = "public class ForceOpenClass1 {\n"
0549: + " ForceOpenClass2 class2;\n"
0550: + " ForceOpenClass3 class3;\n\n"
0551: + " public ForceOpenClass1() {\n"
0552: + " class2 = new ForceOpenClass2();\n"
0553: + " class3 = new ForceOpenClass3();\n"
0554: + " }\n"
0555: + "}";
0556:
0557: IOUtil.writeStringToFile(forceOpenClass1_file,
0558: forceOpenClass1_string);
0559: forceOpenClass1_file.deleteOnExit();
0560:
0561: //_frame.setVisible(true);
0562: Utilities.invokeAndWait(new Runnable() {
0563: public void run() {
0564: _frame.pack();
0565: _frame.open(new FileOpenSelector() {
0566: public File[] getFiles() {
0567: File[] return_me = new File[1];
0568: return_me[0] = new File(_tempDir,
0569: "ForceOpenClass1.java");
0570: return return_me;
0571: }
0572: });
0573: }
0574: });
0575: Utilities.clearEventQueue();
0576:
0577: assertTrue(
0578: "the save button should not be enabled after opening a document",
0579: !_frame.saveEnabledHuh());
0580: _log.log("testSaveButtonEnabled completed");
0581: }
0582:
0583: /** A Test to guarantee that the Dancing UI bug will not rear its ugly head again.
0584: * Basically, add a component listener to the leftComponent of _docSplitPane and
0585: * make certain its size does not change while compiling a class which depends on
0586: * another class.
0587: */
0588: public void testDancingUIFileOpened() throws IOException {
0589: //System.out.println("DEBUG: Entering messed up test");
0590: /** Maybe this sequence of calls should be incorporated into one function createTestDir(), which would get
0591: * the username and create the temporary directory. Only sticky part is deciding where to put it, in FileOps
0592: * maybe?
0593: */
0594:
0595: _log.log("Starting testingDancingUIFileOpened");
0596:
0597: final GlobalModel _model = _frame.getModel();
0598:
0599: String user = System.getProperty("user.name");
0600: _tempDir = IOUtil.createAndMarkTempDirectory("DrJava-test-"
0601: + user, "");
0602:
0603: File forceOpenClass1_file = new File(_tempDir,
0604: "ForceOpenClass1.java");
0605: String forceOpenClass1_string = "public class ForceOpenClass1 {\n"
0606: + " ForceOpenClass2 class2;\n"
0607: + " ForceOpenClass3 class3;\n\n"
0608: + " public ForceOpenClass1() {\n"
0609: + " class2 = new ForceOpenClass2();\n"
0610: + " class3 = new ForceOpenClass3();\n"
0611: + " }\n"
0612: + "}";
0613:
0614: File forceOpenClass2_file = new File(_tempDir,
0615: "ForceOpenClass2.java");
0616: String forceOpenClass2_string = "public class ForceOpenClass2 {\n"
0617: + " inx x = 4;\n" + "}";
0618:
0619: File forceOpenClass3_file = new File(_tempDir,
0620: "ForceOpenClass3.java");
0621: String forceOpenClass3_string = "public class ForceOpenClass3 {\n"
0622: + " String s = \"asf\";\n" + "}";
0623:
0624: IOUtil.writeStringToFile(forceOpenClass1_file,
0625: forceOpenClass1_string);
0626: IOUtil.writeStringToFile(forceOpenClass2_file,
0627: forceOpenClass2_string);
0628: IOUtil.writeStringToFile(forceOpenClass3_file,
0629: forceOpenClass3_string);
0630: forceOpenClass1_file.deleteOnExit();
0631: forceOpenClass2_file.deleteOnExit();
0632: forceOpenClass3_file.deleteOnExit();
0633:
0634: _log.log("DancingUIFileOpened Set Up");
0635:
0636: //_frame.setVisible(true);
0637:
0638: // set up listeners and signal flags
0639:
0640: final ComponentAdapter listener = new ComponentAdapter() {
0641: public void componentResized(ComponentEvent event) {
0642: _testFailed = true;
0643: fail("testDancingUI: Open Documents List danced!");
0644: }
0645: };
0646: final SingleDisplayModelFileOpenedListener openListener = new SingleDisplayModelFileOpenedListener();
0647: final SingleDisplayModelCompileListener compileListener = new SingleDisplayModelCompileListener();
0648:
0649: _openDone = false;
0650:
0651: Utilities.invokeAndWait(new Runnable() {
0652: public void run() {
0653: // _frame.setVisible(true);
0654: _frame.pack();
0655: _frame
0656: .addComponentListenerToOpenDocumentsList(listener);
0657: }
0658: });
0659: Utilities.clearEventQueue();
0660:
0661: _model.addListener(openListener);
0662:
0663: _log.log("opening file");
0664:
0665: Utilities.invokeLater(new Runnable() {
0666: public void run() {
0667: _frame.open(new FileOpenSelector() {
0668: public File[] getFiles() {
0669: File[] return_me = new File[1];
0670: return_me[0] = new File(_tempDir,
0671: "ForceOpenClass1.java");
0672: return return_me;
0673: }
0674: });
0675: }
0676: });
0677: Utilities.clearEventQueue();
0678:
0679: /* wait until file has been open and active document changed. */
0680: synchronized (_openLock) {
0681: try {
0682: while (!_openDone)
0683: _openLock.wait();
0684: } catch (InterruptedException e) {
0685: fail(e.toString());
0686: }
0687: }
0688:
0689: _model.removeListener(openListener);
0690:
0691: _log.log("File opened");
0692:
0693: _compileDone = false;
0694: _model.addListener(compileListener);
0695:
0696: // save and compile the new file asynchronously
0697:
0698: Utilities.invokeLater(new Runnable() {
0699: public void run() {
0700: _log.log("saving all files");
0701: _frame._saveAll();
0702: _log.log("invoking compileAll action");
0703: _frame.getCompileAllButton().doClick();
0704: }
0705: });
0706: Utilities.clearEventQueue();
0707:
0708: synchronized (_compileLock) {
0709: try {
0710: while (!_compileDone)
0711: _compileLock.wait();
0712: } catch (InterruptedException e) {
0713: fail(e.toString());
0714: }
0715: }
0716: _log.log("File saved and compiled");
0717:
0718: if (!IOUtil.deleteRecursively(_tempDir))
0719: System.out
0720: .println("Couldn't fully delete directory "
0721: + _tempDir.getAbsolutePath()
0722: + "\nDo it by hand.\n");
0723:
0724: _log.log("testDancingUIFileOpened completed");
0725: }
0726:
0727: /** A Test to guarantee that the Dancing UI bug will not rear its ugly head again. Basically, add a component listener
0728: * to the leftComponent of _docSplitPane and make certain its size does not change while closing an
0729: * OpenDefinitionsDocument outside the event thread.
0730: */
0731: public void testDancingUIFileClosed() throws IOException {
0732: /** Maybe this sequence of calls should be incorporated into one function createTestDir(), which would get the
0733: * username and create the temporary directory. Only sticky part is deciding where to put it, in FileOps maybe?
0734: */
0735: String user = System.getProperty("user.name");
0736: _tempDir = IOUtil.createAndMarkTempDirectory("DrJava-test-"
0737: + user, "");
0738: File forceOpenClass1_file = new File(_tempDir,
0739: "ForceOpenClass1.java");
0740: String forceOpenClass1_string = "public class ForceOpenClass1 {\n"
0741: + " ForceOpenClass2 class2;\n"
0742: + " ForceOpenClass3 class3;\n\n"
0743: + " public ForceOpenClass1() {\n"
0744: + " class2 = new ForceOpenClass2();\n"
0745: + " class3 = new ForceOpenClass3();\n"
0746: + " }\n"
0747: + "}";
0748:
0749: IOUtil.writeStringToFile(forceOpenClass1_file,
0750: forceOpenClass1_string);
0751: forceOpenClass1_file.deleteOnExit();
0752:
0753: final ComponentAdapter listener = new ComponentAdapter() {
0754: public void componentResized(ComponentEvent event) {
0755: _testFailed = true;
0756: fail("testDancingUI: Open Documents List danced!");
0757: }
0758: };
0759: final SingleDisplayModelFileClosedListener closeListener = new SingleDisplayModelFileClosedListener();
0760:
0761: _closeDone = false;
0762: Utilities.invokeAndWait(new Runnable() {
0763: public void run() {
0764: // _frame.setVisible(true);
0765: _frame.pack();
0766: _frame
0767: .addComponentListenerToOpenDocumentsList(listener);
0768: _frame.open(new FileOpenSelector() {
0769: public File[] getFiles() {
0770: File[] return_me = new File[1];
0771: return_me[0] = new File(_tempDir,
0772: "ForceOpenClass1.java");
0773: return return_me;
0774: }
0775: });
0776: _frame.getModel().addListener(closeListener);
0777: }
0778: });
0779: Utilities.clearEventQueue();
0780:
0781: /* Asynchronously close the file */
0782: Utilities.invokeLater(new Runnable() {
0783: public void run() {
0784: _frame.getCloseButton().doClick();
0785: }
0786: });
0787:
0788: _log.log("Waiting for file closing");
0789:
0790: synchronized (_closeLock) {
0791: try {
0792: while (!_closeDone)
0793: _closeLock.wait();
0794: } catch (InterruptedException e) {
0795: fail(e.toString());
0796: }
0797: }
0798:
0799: if (!IOUtil.deleteRecursively(_tempDir)) {
0800: System.out
0801: .println("Couldn't fully delete directory "
0802: + _tempDir.getAbsolutePath()
0803: + "\nDo it by hand.\n");
0804: }
0805: _log.log("testDancingUIFileClosed completed");
0806: }
0807:
0808: /** A CompileListener for SingleDisplayModel (instead of GlobalModel) */
0809: class SingleDisplayModelCompileListener extends
0810: GlobalModelTestCase.TestListener implements
0811: GlobalModelListener {
0812:
0813: @Override
0814: public void compileStarted() {
0815: }
0816:
0817: /** Just notify when the compile has ended */
0818: @Override
0819: public void compileEnded(File workDir,
0820: List<? extends File> excludedFiles) {
0821: synchronized (_compileLock) {
0822: _compileDone = true;
0823: _compileLock.notify();
0824: }
0825: }
0826:
0827: @Override
0828: public void fileOpened(OpenDefinitionsDocument doc) {
0829: }
0830:
0831: @Override
0832: public void activeDocumentChanged(OpenDefinitionsDocument active) {
0833: }
0834: }
0835:
0836: /** A FileClosedListener for SingleDisplayModel (instead of GlobalModel) */
0837: class SingleDisplayModelFileOpenedListener extends
0838: GlobalModelTestCase.TestListener implements
0839: GlobalModelListener {
0840:
0841: @Override
0842: public void fileClosed(OpenDefinitionsDocument doc) {
0843: }
0844:
0845: @Override
0846: public void fileOpened(OpenDefinitionsDocument doc) {
0847: }
0848:
0849: @Override
0850: public void newFileCreated(OpenDefinitionsDocument doc) {
0851: }
0852:
0853: @Override
0854: public void activeDocumentChanged(OpenDefinitionsDocument doc) {
0855: synchronized (_openLock) {
0856: _openDone = true;
0857: _openLock.notify();
0858: }
0859: }
0860: }
0861:
0862: /** A FileClosedListener for SingleDisplayModel (instead of GlobalModel) */
0863: class SingleDisplayModelFileClosedListener extends
0864: GlobalModelTestCase.TestListener implements
0865: GlobalModelListener {
0866:
0867: @Override
0868: public void fileClosed(OpenDefinitionsDocument doc) {
0869: synchronized (_closeLock) {
0870: _closeDone = true;
0871: _closeLock.notify();
0872: }
0873: }
0874:
0875: @Override
0876: public void fileOpened(OpenDefinitionsDocument doc) {
0877: }
0878:
0879: @Override
0880: public void newFileCreated(OpenDefinitionsDocument doc) {
0881: }
0882:
0883: @Override
0884: public void activeDocumentChanged(OpenDefinitionsDocument active) {
0885: }
0886: }
0887:
0888: /** Create a new temporary file in _tempDir. */
0889: protected File tempFile(String fileName) throws IOException {
0890: File f = File.createTempFile(fileName, ".java", _tempDir)
0891: .getCanonicalFile();
0892: f.deleteOnExit();
0893: return f;
0894: }
0895:
0896: /** Tests that "go to file under cursor" works if unique. */
0897: public void testGotoFileUnderCursor() throws IOException {
0898: // Utilities.show("Running testGotoFileUnderCursor");
0899: String user = System.getProperty("user.name");
0900: _tempDir = IOUtil.createAndMarkTempDirectory("DrJava-test-"
0901: + user, "");
0902:
0903: final File goto1_file = new File(_tempDir,
0904: "GotoFileUnderCursor1.java");
0905: String goto1_string = "GotoFileUnderCursorTest";
0906: IOUtil.writeStringToFile(goto1_file, goto1_string);
0907: goto1_file.deleteOnExit();
0908:
0909: final File goto2_file = new File(_tempDir,
0910: "GotoFileUnderCursorTest.java");
0911: String goto2_string = "GotoFileUnderCursor1";
0912: IOUtil.writeStringToFile(goto2_file, goto2_string);
0913: goto2_file.deleteOnExit();
0914:
0915: Utilities.invokeAndWait(new Runnable() {
0916: public void run() {
0917: _frame.pack();
0918: _frame.open(new FileOpenSelector() {
0919: public File[] getFiles() {
0920: return new File[] { goto1_file, goto2_file };
0921: }
0922: });
0923: }
0924: });
0925:
0926: Utilities.invokeAndWait(new Runnable() {
0927: public void run() {
0928: _frame.initGotoFileDialog();
0929: _frame._gotoFileDialog
0930: .addWindowListener(new WindowListener() {
0931: public void windowActivated(WindowEvent e) {
0932: throw new RuntimeException(
0933: "Should not activate _gotoFileDialog");
0934: }
0935:
0936: public void windowClosed(WindowEvent e) {
0937: throw new RuntimeException(
0938: "Should not close _gotoFileDialog");
0939: }
0940:
0941: public void windowClosing(WindowEvent e) {
0942: throw new RuntimeException(
0943: "Should not be closing _gotoFileDialog");
0944: }
0945:
0946: public void windowDeactivated(WindowEvent e) {
0947: throw new RuntimeException(
0948: "Should not deactivate _gotoFileDialog");
0949: }
0950:
0951: public void windowDeiconified(WindowEvent e) {
0952: throw new RuntimeException(
0953: "Should not deiconify _gotoFileDialog");
0954: }
0955:
0956: public void windowIconified(WindowEvent e) {
0957: throw new RuntimeException(
0958: "Should not iconify _gotoFileDialog");
0959: }
0960:
0961: public void windowOpened(WindowEvent e) {
0962: throw new RuntimeException(
0963: "Should not open _gotoFileDialog");
0964: }
0965: });
0966: }
0967: });
0968:
0969: Utilities.clearEventQueue();
0970: SingleDisplayModel model = _frame.getModel();
0971: OpenDefinitionsDocument goto1_doc = model
0972: .getDocumentForFile(goto1_file);
0973: OpenDefinitionsDocument goto2_doc = model
0974: .getDocumentForFile(goto2_file);
0975: model.setActiveDocument(model.getDocumentForFile(goto1_file));
0976: assertEquals("Document contains the incorrect text",
0977: goto1_string, model.getActiveDocument().getText());
0978:
0979: Utilities.invokeAndWait(new Runnable() {
0980: public void run() {
0981: _frame._gotoFileUnderCursor();
0982: }
0983: });
0984:
0985: Utilities.clearEventQueue();
0986: assertEquals("Incorrect active document; did not go to?",
0987: goto2_doc, model.getActiveDocument());
0988:
0989: Utilities.invokeAndWait(new Runnable() {
0990: public void run() {
0991: _frame._gotoFileUnderCursor();
0992: }
0993: });
0994:
0995: Utilities.clearEventQueue();
0996: assertEquals("Incorrect active document; did not go to?",
0997: goto1_doc, model.getActiveDocument());
0998:
0999: _log.log("gotoFileUnderCursor completed");
1000: }
1001:
1002: /** Tests that "go to file under cursor" works if unique after appending ".java" */
1003: public void testGotoFileUnderCursorAppendJava() throws IOException {
1004: String user = System.getProperty("user.name");
1005: _tempDir = IOUtil.createAndMarkTempDirectory("DrJava-test-"
1006: + user, "");
1007:
1008: final File goto1_file = new File(_tempDir,
1009: "GotoFileUnderCursor2Test.java");
1010: String goto1_string = "GotoFileUnderCursor2";
1011: IOUtil.writeStringToFile(goto1_file, goto1_string);
1012: goto1_file.deleteOnExit();
1013:
1014: final File goto2_file = new File(_tempDir,
1015: "GotoFileUnderCursor2.java");
1016: String goto2_string = "GotoFileUnderCursor2Test";
1017: IOUtil.writeStringToFile(goto2_file, goto2_string);
1018: goto2_file.deleteOnExit();
1019:
1020: Utilities.invokeAndWait(new Runnable() {
1021: public void run() {
1022: _frame.pack();
1023: _frame.open(new FileOpenSelector() {
1024: public File[] getFiles() {
1025: return new File[] { goto1_file, goto2_file };
1026: }
1027: });
1028: }
1029: });
1030:
1031: Utilities.clearEventQueue();
1032:
1033: Utilities.invokeAndWait(new Runnable() {
1034: public void run() {
1035: _frame.initGotoFileDialog();
1036: _frame._gotoFileDialog
1037: .addWindowListener(new WindowListener() {
1038: public void windowActivated(WindowEvent e) {
1039: throw new RuntimeException(
1040: "Should not activate _gotoFileDialog");
1041: }
1042:
1043: public void windowClosed(WindowEvent e) {
1044: throw new RuntimeException(
1045: "Should not close _gotoFileDialog");
1046: }
1047:
1048: public void windowClosing(WindowEvent e) {
1049: throw new RuntimeException(
1050: "Should not be closing _gotoFileDialog");
1051: }
1052:
1053: public void windowDeactivated(WindowEvent e) {
1054: throw new RuntimeException(
1055: "Should not deactivate _gotoFileDialog");
1056: }
1057:
1058: public void windowDeiconified(WindowEvent e) {
1059: throw new RuntimeException(
1060: "Should not deiconify _gotoFileDialog");
1061: }
1062:
1063: public void windowIconified(WindowEvent e) {
1064: throw new RuntimeException(
1065: "Should not iconify _gotoFileDialog");
1066: }
1067:
1068: public void windowOpened(WindowEvent e) {
1069: throw new RuntimeException(
1070: "Should not open _gotoFileDialog");
1071: }
1072: });
1073: }
1074: });
1075:
1076: Utilities.clearEventQueue();
1077:
1078: SingleDisplayModel model = _frame.getModel();
1079: OpenDefinitionsDocument goto1_doc = model
1080: .getDocumentForFile(goto1_file);
1081: OpenDefinitionsDocument goto2_doc = model
1082: .getDocumentForFile(goto2_file);
1083: model.setActiveDocument(model.getDocumentForFile(goto1_file));
1084: assertEquals("Document contains the incorrect text",
1085: goto1_string, model.getActiveDocument().getText());
1086:
1087: Utilities.invokeAndWait(new Runnable() {
1088: public void run() {
1089: _frame._gotoFileUnderCursor();
1090: }
1091: });
1092:
1093: Utilities.clearEventQueue();
1094:
1095: assertEquals("Incorrect active document; did not go to?",
1096: goto2_doc, model.getActiveDocument());
1097:
1098: Utilities.invokeAndWait(new Runnable() {
1099: public void run() {
1100: _frame._gotoFileUnderCursor();
1101: }
1102: });
1103:
1104: Utilities.clearEventQueue();
1105: assertEquals("Incorrect active document; did not go to?",
1106: goto1_doc, model.getActiveDocument());
1107:
1108: _log.log("gotoFileUnderCursorAppendJava completed");
1109: }
1110:
1111: /** Tests that "go to file under cursor" displays the dialog if choice is not unique */
1112: public void testGotoFileUnderCursorShowDialog() throws IOException {
1113: // Utilities.show("Running testGotoFileUnderCursorShowDialog()");
1114: String user = System.getProperty("user.name");
1115: _tempDir = IOUtil.createAndMarkTempDirectory("DrJava-test-"
1116: + user, "");
1117:
1118: final File goto1_file = new File(_tempDir,
1119: "GotoFileUnderCursor3.java");
1120: String goto1_string = "GotoFileUnderCursor";
1121: IOUtil.writeStringToFile(goto1_file, goto1_string);
1122: goto1_file.deleteOnExit();
1123:
1124: final File goto2_file = new File(_tempDir,
1125: "GotoFileUnderCursor4.java");
1126: String goto2_string = "GotoFileUnderCursor3";
1127: IOUtil.writeStringToFile(goto2_file, goto2_string);
1128: goto2_file.deleteOnExit();
1129:
1130: Utilities.invokeAndWait(new Runnable() {
1131: public void run() {
1132: _frame.pack();
1133: _frame.open(new FileOpenSelector() {
1134: public File[] getFiles() {
1135: return new File[] { goto1_file, goto2_file };
1136: }
1137: });
1138: }
1139: });
1140:
1141: final int[] count = new int[2];
1142: Utilities.invokeAndWait(new Runnable() {
1143: public void run() {
1144: _frame.initGotoFileDialog();
1145: _frame._gotoFileDialog
1146: .addWindowListener(new WindowListener() {
1147: public void windowActivated(WindowEvent e) {
1148: ++count[0];
1149: }
1150:
1151: public void windowClosed(WindowEvent e) {
1152: throw new RuntimeException(
1153: "Should not close _gotoFileDialog");
1154: }
1155:
1156: public void windowClosing(WindowEvent e) {
1157: throw new RuntimeException(
1158: "Should not be closing _gotoFileDialog");
1159: }
1160:
1161: public void windowDeactivated(WindowEvent e) { /* throw new RuntimeException("Should not deactivate _gotoFileDialog"); */
1162: }
1163:
1164: public void windowDeiconified(WindowEvent e) {
1165: throw new RuntimeException(
1166: "Should not deiconify _gotoFileDialog");
1167: }
1168:
1169: public void windowIconified(WindowEvent e) {
1170: throw new RuntimeException(
1171: "Should not iconify _gotoFileDialog");
1172: }
1173:
1174: public void windowOpened(WindowEvent e) {
1175: ++count[1];
1176: }
1177: });
1178: }
1179: });
1180:
1181: Utilities.clearEventQueue();
1182:
1183: SingleDisplayModel model = _frame.getModel();
1184: OpenDefinitionsDocument goto1_doc = model
1185: .getDocumentForFile(goto1_file);
1186: OpenDefinitionsDocument goto2_doc = model
1187: .getDocumentForFile(goto2_file);
1188: model.setActiveDocument(model.getDocumentForFile(goto1_file));
1189:
1190: assertEquals("Document contains the incorrect text",
1191: goto1_string, model.getActiveDocument().getText());
1192:
1193: Utilities.invokeAndWait(new Runnable() {
1194: public void run() {
1195: _frame._gotoFileUnderCursor();
1196: }
1197: });
1198: Utilities.clearEventQueue(); // wait for any asynchronous actions to complete
1199:
1200: /* The following test was commented out before test following it was. It presumably fails even if
1201: * the "MainFrame.this.isVisible()" test mentioned below is removed from _gotoFileUnderCursor */
1202: // assertEquals("Did not activate _gotoFileDialog", 1, count[0]);
1203: /* The following test was commented out after suppressing this display when _frame is not visible. If it is
1204: * uncommented, then the "MainFrame.this.isVisible()" test in _gotoFileDialog must be removed. */
1205: // assertEquals("Did not open _gotoFileDialog", 1, count[1]);
1206: _log.log("gotoFileUnderCursorShowDialog completed");
1207: }
1208: }
|