/** * This file Copyright (c) 2005-2008 Aptana, Inc. This program is * dual-licensed under both the Aptana Public License and the GNU General * Public license. You may elect to use one or the other of these licenses. * * This program is distributed in the hope that it will be useful, but * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or * NONINFRINGEMENT. Redistribution, except as permitted by whichever of * the GPL or APL you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or modify this * program under the terms of the GNU General Public License, * Version 3, as published by the Free Software Foundation. You should * have received a copy of the GNU General Public License, Version 3 along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Aptana provides a special exception to allow redistribution of this file * with certain other free and open source software ("FOSS") code and certain additional terms * pursuant to Section 7 of the GPL. You may view the exception and these * terms on the web at http://www.aptana.com/legal/gpl/. * * 2. For the Aptana Public License (APL), this program and the * accompanying materials are made available under the terms of the APL * v1.0 which accompanies this distribution, and is available at * http://www.aptana.com/legal/apl/. * * You may view the GPL, Aptana's exception and additional terms, and the * APL in the file titled license.html at the root of the corresponding * plugin containing this source file. * * Any modifications to this file must keep this entire header intact. */ package com.aptana.ide.editors.junit.js; import junit.framework.TestCase; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.Path; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PlatformUI; import com.aptana.ide.editor.js.JSEditor; import com.aptana.ide.editor.js.JSLanguageEnvironment; import com.aptana.ide.editor.js.parsing.JSMimeType; import com.aptana.ide.editor.js.runtime.Environment; import com.aptana.ide.editor.js.runtime.IObject; import com.aptana.ide.editor.js.runtime.IScope; import com.aptana.ide.editor.js.runtime.JSFunction; import com.aptana.ide.editor.js.runtime.JSString; import com.aptana.ide.editor.scriptdoc.parsing.FunctionDocumentation; import com.aptana.ide.editors.junit.GenericProject; import com.aptana.ide.editors.junit.ProjectTestUtils; import com.aptana.ide.editors.junit.TestProject; import com.aptana.ide.editors.junit.TestUtils; import com.aptana.ide.editors.managers.FileContextManager; import com.aptana.ide.editors.unified.ILanguageEnvironment; import com.aptana.ide.metadata.IDocumentation; /** * @author Robin */ public class JSTodoTests extends TestCase { private GenericProject project; private ILanguageEnvironment env; private Environment jsEnv; private IScope global; // private IObject undef; private SourceViewer viewer; private IDocument document; private IContentAssistProcessor caProcessor; private ICompletionProposal[] props; private String[] fileList = new String[] { "globalVsLocal.js", "reinitObjects.js", "conditionals.js", "arrays.js", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "multipleTypes.js", "multipleDocs.js", "expressions.js", "dynamicCreation.js", "selfInvokingFns.js", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ "doubleNamedFns.js", "conditionalUsage.js", "specializedMethods.js", "dataHiding.js", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ "multipleAssignments.js", "builtIns.js" }; //$NON-NLS-1$ //$NON-NLS-2$ /** * ProfileManagerTest */ public JSTodoTests() { project = GenericProject.getInstance(); env = JSLanguageEnvironment.getInstance(); jsEnv = (Environment) env.getRuntimeEnvironment(); global = jsEnv.getGlobal(); // undef = JSUndefined.getSingletonInstance(); } /** * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { super.setUp(); } /** * @see junit.framework.TestCase#tearDown() */ protected void tearDown() throws Exception { super.tearDown(); } /** * testAllCases */ public void testAllCases() { for (int i = 0; i < fileList.length; i++) { String name = fileList[i]; Path path = ProjectTestUtils.findFileInPlugin(TestProject.PLUGIN_ID, "jsTodo/" + name); //$NON-NLS-1$ //$NON-NLS-2$ IFile curFile = ProjectTestUtils.addFileToProject(path, this.project.getProject()); ProjectTestUtils.openInEditor(curFile, ProjectTestUtils.JS_EDITOR_ID); TestUtils.waitForParse(2000); IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); IEditorPart part = page.getActiveEditor(); if (part instanceof JSEditor) { JSEditor jsSourceEditor = (JSEditor) part; viewer = (SourceViewer) jsSourceEditor.getViewer(); caProcessor = jsSourceEditor.getBaseContributor() .getContentAssistProcessor(viewer, JSMimeType.MimeType); document = viewer.getDocument(); } TestUtils.waitForParse(2500); runTest(i); ProjectTestUtils.closeEditor(part); } // *********************************************************************** // open testObj.html from project // globalVsLocal(); } private ICompletionProposal getProposal(String name) { ICompletionProposal result = null; if (props == null) { return null; } for (int i = 0; i < props.length; i++) { ICompletionProposal prop = props[i]; if (prop.getDisplayString().equals(name)) { result = prop; break; } } return result; } private void runTest(int index) { switch (index) { case 0: globalVsLocal(); break; case 1: reinitObjects(); break; case 2: conditionals(); break; case 3: arrays(); break; case 4: multipleTypes(); break; case 5: multipleDocs(); break; case 6: expressions(); break; case 7: dynamicCreation(); break; case 8: selfInvokingFns(); break; case 9: doubleNamedFns(); break; case 10: conditionalUsage(); break; case 11: specializedMethods(); break; case 12: dataHiding(); break; case 13: multipleAssignments(); break; case 14: builtIns(); break; default: break; } } private void globalVsLocal() { // /** global x */ // var x = 5; // /** global y */ // var y = 1; // (58) // /** // * // * @param {Object} y arg y // */ // function foo(y) // { // y = 2; // arg // x = 6; // global // (161) // var x = "test"; // x = "test2"; // local // (209) // } int probeLocation = getTestLocation(0); invokeCodeAssistAt(probeLocation); int fileIndex = FileContextManager.CURRENT_FILE_INDEX; IObject xobj = global.getPropertyValue("x", fileIndex, probeLocation); //$NON-NLS-1$ String xdoc = xobj.getDocumentation().getDescription().trim(); assertEquals(xdoc, "global x"); //$NON-NLS-1$ IObject yobj = global.getPropertyValue("y", fileIndex, probeLocation); //$NON-NLS-1$ String ydoc = yobj.getDocumentation().getDescription().trim(); assertEquals(ydoc, "global y"); //$NON-NLS-1$ probeLocation = getTestLocation(1); invokeCodeAssistAt(probeLocation); JSFunction fn = (JSFunction) global.getPropertyValue("foo", fileIndex, probeLocation); //$NON-NLS-1$ IScope scope = fn.getBodyScope(); // IObject yarg = scope.getLocalProperty("y").getValue(fileIndex, probeLocation); // IObject yarg = scope.getPropertyValue("y", fileIndex, probeLocation); // fails: this doc shouldn't be null // String yargdoc = yarg.getDocumentation().getDescription().trim(); String yargdoc = ((FunctionDocumentation) fn.getDocumentation()).getParams()[0].getDescription().trim(); assertEquals(yargdoc, "arg y"); //$NON-NLS-1$ // test directly on CA // ICompletionProposal prop = getProposal("y"); // String displayInfo = prop.getAdditionalProposalInfo(); // assertTrue(displayInfo.indexOf("arg y") > -1); // this fails, should be arg info // test directly off CA // prop = getProposal("x"); // String xdisplayInfo = prop.getAdditionalProposalInfo(); // fails - no doc available // assertTrue(xdisplayInfo.indexOf("global x") > -1); probeLocation = getTestLocation(2); invokeCodeAssistAt(probeLocation); IObject localx = scope.getPropertyValue("x", fileIndex, probeLocation); //$NON-NLS-1$ IDocumentation localxdoc = localx.getDocumentation(); assertNull(localxdoc); assertTrue(localx instanceof JSString); IObject type = localx.getPropertyValue("constructor", fileIndex, probeLocation); //$NON-NLS-1$ assertEquals(type.getClassName(), "Function"); //$NON-NLS-1$ // prop = getProposal("x"); // xdisplayInfo = prop.getAdditionalProposalInfo(); // this fails, it gets the global doc instead // assertTrue(displayInfo.indexOf("global x") == -1); } private void reinitObjects() { // var obj = {}; // obj.x = 5; // obj = {}; // obj.y = 6; // // obj only contains a y property, x is undefined int probeLocation = getTestLocation(0); invokeCodeAssistAt(probeLocation); // ICompletionProposal propx = getProposal("x"); ICompletionProposal propy = getProposal("y"); //$NON-NLS-1$ // assertNull(propx); This Fails! should be null assertNotNull(propy); } private void conditionals() { // // file 1 // /** doc for ns */ // var ns = {}; // ns.x = 5; // // // file 2 // if(ns == null) // { // var ns = {}; // } // ns.y = 6; // // // in this case ns should have both x and y // // problem is, compare with the last case, and now... // // if(true) // { // var ns = {}; // } // ns.z = 7; // now ns should only have a 'z' property int probeLocation = getTestLocation(0); invokeCodeAssistAt(probeLocation); ICompletionProposal propx = getProposal("x"); //$NON-NLS-1$ ICompletionProposal propy = getProposal("y"); //$NON-NLS-1$ ICompletionProposal propz = getProposal("y"); //$NON-NLS-1$ assertNotNull(propx); // assertNull(propy); //This Fails! should be null // assertNull(propz); //This Fails! should be null probeLocation = getTestLocation(1); invokeCodeAssistAt(probeLocation); propx = getProposal("x"); //$NON-NLS-1$ propy = getProposal("y"); //$NON-NLS-1$ propz = getProposal("y"); //$NON-NLS-1$ assertNotNull(propx); assertNotNull(propy); // assertNull(propz); //This Fails! should be null probeLocation = getTestLocation(2); invokeCodeAssistAt(probeLocation); propx = getProposal("x"); //$NON-NLS-1$ propy = getProposal("y"); //$NON-NLS-1$ propz = getProposal("y"); //$NON-NLS-1$ // assertNull(propx); //This Fails! should be null // assertNull(propy); //This Fails! should be null assertNotNull(propz); } private void arrays() { // var ar = [1,"two",obj]; // ar[2]. // // how can we even sdoc this? // // also these types can be changed, created dynamically etc. int probeLocation = getTestLocation(0); invokeCodeAssistAt(probeLocation); // ICompletionProposal ar2 = getProposal("charAt"); // should be string // assertNotNull(ar2); // fails! can't get string. } private void multipleTypes() { // var x = 5; // x = "string"; // x. // // we support multiple types in the sdoc format // // we can derive there are multiple types from the info we have // // we need to actually add this the the code assist dialog int probeLocation = getTestLocation(0); invokeCodeAssistAt(probeLocation); // ICompletionProposal isNum = getProposal("toExponential"); // should be string // assertNotNull(isNum); // fails! can't get string. } private void multipleDocs() { // /** doc1 */ // var x = true; // x ; // /** doc2 */ // x = false; // x ; // /** doc3 */ // var y = x; // y ; // function foo(arg) // { // /** doc4 */ // y = arg; // y ; // } // // these docs all point to the same object // // there are various ways docs can be assigned multiple times like this // // this is esp tricky with namespaces, where conditional reassignments are common // // // // // // /** doc1 */ // var x = 5; // /** doc2 */ // var y = 6; // var z = (test) ? x : y; // z ; int probeLocation = getTestLocation(0); invokeCodeAssistAt(probeLocation); ICompletionProposal prop = getProposal("x"); // should be doc1 //$NON-NLS-1$ assertTrue(prop.getAdditionalProposalInfo().indexOf("doc1") > -1); //$NON-NLS-1$ probeLocation = getTestLocation(1); invokeCodeAssistAt(probeLocation); prop = getProposal("x"); // should be doc2, and doc1 //$NON-NLS-1$ assertTrue(prop.getAdditionalProposalInfo().indexOf("doc2") > -1); //$NON-NLS-1$ // assertTrue(prop.getAdditionalProposalInfo().indexOf("doc1") > -1); // fails probeLocation = getTestLocation(2); invokeCodeAssistAt(probeLocation); prop = getProposal("y"); // should be doc3,2,1, but not doc4 //$NON-NLS-1$ // we actually end up with doc4 // assertTrue(prop.getAdditionalProposalInfo().indexOf("doc4") == -1); // assertTrue(prop.getAdditionalProposalInfo().indexOf("doc1") > -1); // assertTrue(prop.getAdditionalProposalInfo().indexOf("doc2") > -1); // assertTrue(prop.getAdditionalProposalInfo().indexOf("doc3") > -1); // assertTrue(prop.getAdditionalProposalInfo().indexOf("doc1") > -1); // fails probeLocation = getTestLocation(3); invokeCodeAssistAt(probeLocation); prop = getProposal("y"); // should be doc4,3,2,1 //$NON-NLS-1$ // assertTrue(prop.getAdditionalProposalInfo().indexOf("doc1") > -1); // assertTrue(prop.getAdditionalProposalInfo().indexOf("doc2") > -1); // assertTrue(prop.getAdditionalProposalInfo().indexOf("doc3") > -1); assertTrue(prop.getAdditionalProposalInfo().indexOf("doc4") > -1); //$NON-NLS-1$ probeLocation = getTestLocation(4); invokeCodeAssistAt(probeLocation); prop = getProposal("z"); // should be doc2, and doc1 //$NON-NLS-1$ // instead it is null // assertTrue(prop.getAdditionalProposalInfo().indexOf("doc1") > -1); // assertTrue(prop.getAdditionalProposalInfo().indexOf("doc2") > -1); } private void expressions() { // // we currently don't support expressions at all // /** doc */ // var x = 5 + 6; // var y = x + x; // neither x nor y will show up in the environment" int probeLocation = getTestLocation(0); invokeCodeAssistAt(probeLocation); // ICompletionProposal propx = getProposal("x"); // ICompletionProposal propy = getProposal("y"); // assertNotNull(propx); // fails! x is null // assertNotNull(propy); // fails! y is null } private void dynamicCreation() { // var obj = {}; // obj.foo = function (){}; // obj.foo.prototype.x = 5; // // var a = new obj["foo"](); // key line // a. // // // var obj = {}; // var index = 1; // obj.x0 = 5; // obj.x1 = 5; // obj.x2 = 5; // var z = obj["x" + index]; // z. int probeLocation = getTestLocation(0); invokeCodeAssistAt(probeLocation); // ICompletionProposal xprop = getProposal("toExponential"); // should be number probeLocation = getTestLocation(1); invokeCodeAssistAt(probeLocation); // ICompletionProposal zprop = getProposal("toExponential"); // should be number // note: testing for number doesn't work here - test for // assertNotNull(xprop); // fails! x not number // assertNotNull(zprop); // fails! z not number } private void selfInvokingFns() { // var f = function foo(arg1, {obj:4}) // { // return 5; // }(); // note invocation at end // // // f should be 5 int probeLocation = getTestLocation(0); invokeCodeAssistAt(probeLocation); // ICompletionProposal isNum = getProposal("toExponential"); // should be number // assertNotNull(isNum); // fails! f not a number } private void doubleNamedFns() { // /** doc */ // var x = function foo() // { // } // // need to be sure both cases are handled, and both can access the doc (they are now) int probeLocation = getTestLocation(0); invokeCodeAssistAt(probeLocation); ICompletionProposal xprop = getProposal("x"); //$NON-NLS-1$ // ICompletionProposal fooprop = getProposal("foo"); assertNotNull(xprop); // hmm, this shouldn't be null - it shows up in CA in the ide... // assertNotNull(fooprop); } private void conditionalUsage() { int probeLocation = 0; invokeCodeAssistAt(probeLocation); // ICompletionProposal isNum = getProposal("toExponential"); } private void specializedMethods() { int probeLocation = 0; invokeCodeAssistAt(probeLocation); // ICompletionProposal isNum = getProposal("toExponential"); } private void dataHiding() { int probeLocation = 0; invokeCodeAssistAt(probeLocation); // ICompletionProposal isNum = getProposal("toExponential"); } private void multipleAssignments() { // /** doc */ // var A = B = function(iterable) {} // int probeLocation = getTestLocation(0); invokeCodeAssistAt(probeLocation); ICompletionProposal prop1 = getProposal("A"); // should be fn //$NON-NLS-1$ // ICompletionProposal prop2 = getProposal("B"); // should be fn assertTrue(prop1.getAdditionalProposalInfo().indexOf("doc") > -1); //$NON-NLS-1$ // fails, we don't get second assignment // assertTrue(prop2.getAdditionalProposalInfo().indexOf("doc") > -1); } private void builtIns() { int probeLocation = 0; invokeCodeAssistAt(probeLocation); // ICompletionProposal isNum = getProposal("toExponential"); } private void invokeCodeAssistAt(int position) { viewer.setSelectedRange(position, 0); viewer.doOperation(SourceViewer.CONTENTASSIST_CONTEXT_INFORMATION); props = caProcessor.computeCompletionProposals(viewer, position); } /** * @param i * @return int */ private int getTestLocation(int i) { return document.get().indexOf("/* #" + i + " */") - 1; //$NON-NLS-1$ //$NON-NLS-2$ } }