/** * Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package org.python.pydev.parser; import java.util.HashMap; import java.util.Map; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.preference.PreferenceStore; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.ui.IEditorInput; import org.python.pydev.core.IGrammarVersionProvider; import org.python.pydev.core.IIndentPrefs; import org.python.pydev.core.IPyEdit; import org.python.pydev.core.IPythonNature; import org.python.pydev.core.parser.IPyParser; import org.python.pydev.shared_core.editor.IBaseEditor; import org.python.pydev.shared_core.model.IModelListener; import org.python.pydev.shared_core.model.ISimpleNode; import junit.framework.TestCase; public class PyParserEditorIntegrationTest extends TestCase { static class PyEditStub implements IPyEdit { public IDocument doc; public int parserChanged; private Map<String, Object> cache = new HashMap<String, Object>(); private PydevFileEditorInputStub pydevFileEditorInputStub; public PyEditStub(IDocument doc, PydevFileEditorInputStub pydevFileEditorInputStub) { this.doc = doc; this.pydevFileEditorInputStub = pydevFileEditorInputStub; } @Override public IEditorInput getEditorInput() { return pydevFileEditorInputStub; } @Override public IPythonNature getPythonNature() { return new PythonNatureStub(); } public void setParser(IPyParser parser) { throw new RuntimeException("Not implemented"); } @Override public void parserChanged(ISimpleNode root, IAdaptable file, IDocument doc, long docModificationStamp) { this.parserChanged += 1; } @Override public void parserError(Throwable error, IAdaptable file, IDocument doc) { throw new RuntimeException("Not implemented"); } @Override public Map<String, Object> getCache() { return this.cache; } @Override public <T> T getAdapter(Class<T> adapter) { return null; } @Override public boolean hasSameInput(IBaseEditor edit) { if (this == edit) { throw new RuntimeException( "Cannot compare when it's the same... it should change the document in this case"); } if (edit.getEditorInput() == getEditorInput()) { return true; } return false; } @Override public IDocument getDocument() { return doc; } public void setDocument(IDocument doc) { this.doc = doc; } public void setInput(PydevFileEditorInputStub input) { this.pydevFileEditorInputStub = input; } @Override public void setStatusLineErrorMessage(String msg) { throw new RuntimeException("Not implemented"); } @Override public IGrammarVersionProvider getGrammarVersionProvider() { return this.getPythonNature(); } @Override public IIndentPrefs getIndentPrefs() { throw new RuntimeException("Not implemented"); } @Override public Object getFormatStd() { throw new RuntimeException("Not implemented"); } @Override public void addModelListener(IModelListener modelListener) { throw new RuntimeException("Not implemented"); } @Override public void removeModelListener(IModelListener modelListener) { throw new RuntimeException("Not implemented"); } } public static void main(String[] args) { try { PyParserEditorIntegrationTest test = new PyParserEditorIntegrationTest(); test.setUp(); test.testChangeInput(); test.tearDown(); System.out.println("Finished"); junit.textui.TestRunner.run(PyParserEditorIntegrationTest.class); } catch (Exception e) { e.printStackTrace(); } } @Override protected void setUp() throws Exception { PyParserManager.setPyParserManager(null); } @Override protected void tearDown() throws Exception { PyParserManager.setPyParserManager(null); } public void testIntegration() throws Exception { PreferenceStore preferences = new PreferenceStore(); PyParserManager pyParserManager = PyParserManager.getPyParserManager(preferences); Document doc = new Document(); PyEditStub pyEdit = new PyEditStub(doc, new PydevFileEditorInputStub()); pyParserManager.attachParserTo(pyEdit); checkParserChanged(pyEdit, 1); doc.replace(0, 0, "\r\ntest"); checkParserChanged(pyEdit, 2); pyParserManager.attachParserTo(pyEdit); checkParserChanged(pyEdit, 3); doc.replace(0, 0, "\r\ntest"); //after this change, only 1 reparse should be asked, as the editor and doc is the same checkParserChanged(pyEdit, 4); pyParserManager.notifyEditorDisposed(pyEdit); doc.replace(0, 0, "\r\ntest"); //after this change, only 1 reparse should be asked, as the editor and doc is the same waitABit(); assertEquals(4, pyEdit.parserChanged); assertEquals(0, pyParserManager.getParsers().size()); } public void testDifferentEditorsSameInput() throws Exception { PreferenceStore preferences = new PreferenceStore(); PyParserManager pyParserManager = PyParserManager.getPyParserManager(preferences); Document doc = new Document(); PydevFileEditorInputStub input = new PydevFileEditorInputStub(); //create them with the same input PyEditStub pyEdit1 = new PyEditStub(doc, input); PyEditStub pyEdit2 = new PyEditStub(doc, input); pyParserManager.attachParserTo(pyEdit1); checkParserChanged(pyEdit1, 1); doc.replace(0, 0, "\r\ntest"); checkParserChanged(pyEdit1, 2); pyParserManager.attachParserTo(pyEdit2); checkParserChanged(pyEdit1, 3); checkParserChanged(pyEdit2, 1); IDocument doc2 = new Document(); pyEdit2.setDocument(doc2); pyParserManager.notifyEditorDisposed(pyEdit1); checkParserChanged(pyEdit1, 3); checkParserChanged(pyEdit2, 2); assertNull(pyParserManager.getParser(pyEdit1)); doc2.replace(0, 0, "\r\ntest"); checkParserChanged(pyEdit1, 3); checkParserChanged(pyEdit2, 3); doc.replace(0, 0, "\r\ntest"); //no one's listening this one anymore waitABit(); checkParserChanged(pyEdit1, 3); checkParserChanged(pyEdit2, 3); pyParserManager.notifyEditorDisposed(pyEdit2); assertNull(pyParserManager.getParser(pyEdit2)); doc2.replace(0, 0, "\r\ntest"); //no one's listening this one anymore doc.replace(0, 0, "\r\ntest"); //no one's listening this one anymore waitABit(); checkParserChanged(pyEdit1, 3); checkParserChanged(pyEdit2, 3); assertEquals(0, pyParserManager.getParsers().size()); } public void testChangeInput() throws Exception { PreferenceStore preferences = new PreferenceStore(); PyParserManager pyParserManager = PyParserManager.getPyParserManager(preferences); Document doc = new Document(); PydevFileEditorInputStub input1 = new PydevFileEditorInputStub(); PydevFileEditorInputStub input2 = new PydevFileEditorInputStub(); //create them with the same input PyEditStub pyEdit1 = new PyEditStub(doc, input1); PyEditStub pyEdit2 = new PyEditStub(doc, input2); pyParserManager.attachParserTo(pyEdit1); pyParserManager.attachParserTo(pyEdit2); assertEquals(2, pyParserManager.getParsers().size()); pyEdit2.setInput(input1); pyParserManager.attachParserTo(pyEdit2); assertEquals(1, pyParserManager.getParsers().size()); pyEdit2.setInput(input2); //different input pyParserManager.attachParserTo(pyEdit2); assertEquals(2, pyParserManager.getParsers().size()); pyParserManager.notifyEditorDisposed(pyEdit1); pyParserManager.notifyEditorDisposed(pyEdit2); assertEquals(0, pyParserManager.getParsers().size()); } private void waitABit() throws InterruptedException { for (int i = 0; i < 10; i++) { synchronized (this) { this.wait(25); } } } Object lock = new Object(); private void checkParserChanged(PyEditStub pyEdit, int expected) throws InterruptedException { for (int i = 0; i < 20 && pyEdit.parserChanged < expected; i++) { synchronized (lock) { lock.wait(250); } } assertEquals(expected, pyEdit.parserChanged); } }