/*******************************************************************************
* Copyright (c) 2015 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.cdt.qt.core.tests;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.qt.core.IQMLAnalyzer;
import org.eclipse.cdt.qt.core.QMLTernCompletion;
import org.eclipse.cdt.qt.core.qmljs.IJSBinaryExpression;
import org.eclipse.cdt.qt.core.qmljs.IJSBinaryExpression.BinaryOperator;
import org.eclipse.cdt.qt.core.qmljs.IQmlASTNode;
import org.eclipse.cdt.qt.core.qmljs.IQmlHeaderItem;
import org.eclipse.cdt.qt.core.qmljs.IQmlImport;
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectMember;
import org.eclipse.cdt.qt.core.qmljs.IQmlProgram;
import org.eclipse.cdt.qt.core.qmljs.IQmlPropertyBinding;
import org.eclipse.cdt.qt.core.qmljs.IQmlRootObject;
import org.eclipse.cdt.qt.core.qmljs.IQmlScriptBinding;
import org.junit.BeforeClass;
import org.junit.Test;
@SuppressWarnings("nls")
public class NashornTests {
protected static IQMLAnalyzer analyzer;
@BeforeClass
public static void loadAnalyzer() {
analyzer = Activator.getService(IQMLAnalyzer.class);
}
protected void getCompletions(String code, QMLTernCompletion... expected) throws Throwable {
int pos = code.indexOf('|');
code = code.substring(0, pos) + code.substring(pos + 1);
Collection<QMLTernCompletion> QMLTernCompletions = analyzer.getCompletions("test1.qml", code, pos, false);
Map<String, QMLTernCompletion> set = new HashMap<>();
Set<String> unexpected = new HashSet<>();
for (QMLTernCompletion QMLTernCompletion : expected) {
set.put(QMLTernCompletion.getName(), QMLTernCompletion);
}
for (QMLTernCompletion QMLTernCompletion : QMLTernCompletions) {
String name = QMLTernCompletion.getName();
QMLTernCompletion c = set.get(name);
if (c != null) {
assertEquals(c.getType(), QMLTernCompletion.getType());
assertEquals(c.getOrigin(), QMLTernCompletion.getOrigin());
set.remove(name);
} else {
unexpected.add(name);
}
}
if (!set.isEmpty()) {
fail("Missing names: " + String.join(", ", set.keySet()));
}
if (!unexpected.isEmpty()) {
fail("Unexpected names: " + String.join(", ", unexpected));
}
}
@Test
public void testParseFile1() throws Throwable {
IQmlASTNode node = analyzer.parseFile("main.qml", "");
assertEquals("Unexpected program node type", "QMLProgram", node.getType());
}
@Test
public void testParseFile2() throws Throwable {
IQmlASTNode node = analyzer.parseFile("main.qml", "import QtQuick 2.2");
assertThat(node, instanceOf(IQmlProgram.class));
IQmlProgram program = (IQmlProgram) node;
List<IQmlHeaderItem> headerItems = program.getHeaderItemList().getItems();
assertEquals("Unexpected number of header items", 1, headerItems.size());
assertThat(headerItems.get(0), instanceOf(IQmlImport.class));
IQmlImport imp = (IQmlImport) headerItems.get(0);
assertEquals("Unexpected module identifier", "QtQuick", imp.getModule().getIdentifier().getName());
assertEquals("Unexpected module raw version", "2.2", imp.getModule().getVersion().getRaw());
assertEquals("Unexpected module version", 2.2, imp.getModule().getVersion().getValue(), 0.0001d);
}
@Test
public void testParseString1() throws Throwable {
IQmlASTNode node = analyzer.parseString("", "qml", true, true);
assertEquals("Unexpected program node type", "QMLProgram", node.getType());
}
@Test
public void testParseString2() throws Throwable {
IQmlASTNode node = analyzer.parseString("import QtQuick 2.2", "qml", true, true);
assertThat(node, instanceOf(IQmlProgram.class));
IQmlProgram program = (IQmlProgram) node;
List<IQmlHeaderItem> headerItems = program.getHeaderItemList().getItems();
assertEquals("Unexpected number of header items", 1, headerItems.size());
assertThat(headerItems.get(0), instanceOf(IQmlImport.class));
IQmlImport imp = (IQmlImport) headerItems.get(0);
assertEquals("Unexpected module identifier", "QtQuick", imp.getModule().getIdentifier().getName());
assertEquals("Unexpected module raw version", "2.2", imp.getModule().getVersion().getRaw());
assertEquals("Unexpected module version", 2.2, imp.getModule().getVersion().getValue(), 0.0001d);
}
@Test
public void testParseString3() throws Throwable {
IQmlASTNode node = analyzer.parseString("import QtQuick 2.2", "qml", true, true);
assertThat(node, instanceOf(IQmlProgram.class));
IQmlProgram program = (IQmlProgram) node;
List<IQmlHeaderItem> headerItems = program.getHeaderItemList().getItems();
assertEquals("Unexpected number of header items", 1, headerItems.size());
assertThat(headerItems.get(0), instanceOf(IQmlImport.class));
IQmlImport imp = (IQmlImport) headerItems.get(0);
assertEquals("Unexpected start range", 0, imp.getRange()[0]);
assertEquals("Unexpected end range", 18, imp.getRange()[1]);
}
@Test
public void testParseString4() throws Throwable {
IQmlASTNode node = analyzer.parseString("import QtQuick 2.2", "qml", true, true);
assertThat(node, instanceOf(IQmlProgram.class));
IQmlProgram program = (IQmlProgram) node;
List<IQmlHeaderItem> headerItems = program.getHeaderItemList().getItems();
assertEquals("Unexpected number of header items", 1, headerItems.size());
assertThat(headerItems.get(0), instanceOf(IQmlImport.class));
IQmlImport imp = (IQmlImport) headerItems.get(0);
assertEquals("Unexpected start line", 1, imp.getLocation().getStart().getLine());
assertEquals("Unexpected start column", 0, imp.getLocation().getStart().getColumn());
assertEquals("Unexpected start line", 1, imp.getLocation().getEnd().getLine());
assertEquals("Unexpected start column", 18, imp.getLocation().getEnd().getColumn());
}
@Test
public void testParseString5() throws Throwable {
IQmlASTNode node = analyzer.parseString("QtObject {}", "qml", true, true);
assertThat(node, instanceOf(IQmlProgram.class));
IQmlProgram program = (IQmlProgram) node;
List<IQmlHeaderItem> headerItems = program.getHeaderItemList().getItems();
assertEquals("Unexpected number of header items", 0, headerItems.size());
assertNotNull("Root object was null", program.getRootObject());
IQmlRootObject root = program.getRootObject();
assertEquals("Unexpected root object type", "QMLObjectDefinition", root.getType());
assertEquals("Unexpected root object identifier", "QtObject", root.getIdentifier().getName());
}
@Test
public void testParseString6() throws Throwable {
IQmlASTNode node = analyzer.parseString("QtObject {s: 3 + 3}", "qml", true, true);
assertThat(node, instanceOf(IQmlProgram.class));
IQmlProgram program = (IQmlProgram) node;
assertNotNull("Root object was null", program.getRootObject());
IQmlRootObject root = program.getRootObject();
List<IQmlObjectMember> members = root.getBody().getMembers();
assertEquals("Unexpected number of root object members", 1, members.size());
assertThat(members.get(0), instanceOf(IQmlPropertyBinding.class));
IQmlPropertyBinding bind = (IQmlPropertyBinding) members.get(0);
assertThat(bind.getBinding(), instanceOf(IQmlScriptBinding.class));
IQmlScriptBinding scriptBinding = (IQmlScriptBinding) bind.getBinding();
assertFalse("Script binding was not a JavaScript expression", scriptBinding.isBlock());
assertThat(scriptBinding.getScript(), instanceOf(IJSBinaryExpression.class));
assertEquals("Unexpected expression type", "BinaryExpression", scriptBinding.getScript().getType());
IJSBinaryExpression expr = (IJSBinaryExpression) scriptBinding.getScript();
assertEquals("Unexpected binary operator", BinaryOperator.Add, expr.getOperator());
}
@Test
public void testCompletions1() throws Throwable {
if (analyzer == null) {
return;
}
getCompletions("Window {\n\tproperty int height\n\the|\n}",
new QMLTernCompletion("height", "number", "test1.qml"));
}
@Test
public void testCompletions2() throws Throwable {
if (analyzer == null) {
return;
}
getCompletions("Window {\n\tproperty int height\n\tproperty int width\n\tproperty string text\n\t|\n}",
new QMLTernCompletion("height", "number", "test1.qml"),
new QMLTernCompletion("text", "string", "test1.qml"),
new QMLTernCompletion("width", "number", "test1.qml"));
}
@Test
public void testCompletions3() throws Throwable {
if (analyzer == null) {
return;
}
getCompletions("Window {\n\tproperty int height\n\tObject {\n\t\t|\n\t}\n}");
}
@Test
public void testCompletions4() throws Throwable {
if (analyzer == null) {
return;
}
getCompletions("Window {\n\tproperty var test: |\n}",
new QMLTernCompletion("decodeURI", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("decodeURIComponent", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("encodeURI", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("encodeURIComponent", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("eval", "fn(code: string)", "ecma5"),
new QMLTernCompletion("isFinite", "fn(value: number) -> bool", "ecma5"),
new QMLTernCompletion("isNaN", "fn(value: number) -> bool", "ecma5"),
new QMLTernCompletion("parseFloat", "fn(string: string) -> number", "ecma5"),
new QMLTernCompletion("parseInt", "fn(string: string, radix?: number) -> number", "ecma5"),
new QMLTernCompletion("test", "?", "test1.qml"), new QMLTernCompletion("undefined", "?", "ecma5"),
new QMLTernCompletion("Array", "fn(size: number)", "ecma5"),
new QMLTernCompletion("Boolean", "fn(value: ?) -> bool", "ecma5"),
new QMLTernCompletion("Date", "fn(ms: number)", "ecma5"),
new QMLTernCompletion("Error", "fn(message: string)", "ecma5"),
new QMLTernCompletion("EvalError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("Function", "fn(body: string) -> fn()", "ecma5"),
new QMLTernCompletion("Infinity", "number", "ecma5"), new QMLTernCompletion("JSON", "JSON", "ecma5"),
new QMLTernCompletion("Math", "Math", "ecma5"), new QMLTernCompletion("NaN", "number", "ecma5"),
new QMLTernCompletion("Number", "fn(value: ?) -> number", "ecma5"),
new QMLTernCompletion("Object", "fn()", "ecma5"),
new QMLTernCompletion("RangeError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("ReferenceError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("RegExp", "fn(source: string, flags?: string)", "ecma5"),
new QMLTernCompletion("String", "fn(value: ?) -> string", "ecma5"),
new QMLTernCompletion("SyntaxError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("TypeError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("URIError", "fn(message: string)", "ecma5"));
}
@Test
public void testCompletions5() throws Throwable {
if (analyzer == null) {
return;
}
getCompletions("Window {\n\ttest: |\n}",
new QMLTernCompletion("decodeURI", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("decodeURIComponent", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("encodeURI", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("encodeURIComponent", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("eval", "fn(code: string)", "ecma5"),
new QMLTernCompletion("isFinite", "fn(value: number) -> bool", "ecma5"),
new QMLTernCompletion("isNaN", "fn(value: number) -> bool", "ecma5"),
new QMLTernCompletion("parseFloat", "fn(string: string) -> number", "ecma5"),
new QMLTernCompletion("parseInt", "fn(string: string, radix?: number) -> number", "ecma5"),
new QMLTernCompletion("undefined", "?", "ecma5"),
new QMLTernCompletion("Array", "fn(size: number)", "ecma5"),
new QMLTernCompletion("Boolean", "fn(value: ?) -> bool", "ecma5"),
new QMLTernCompletion("Date", "fn(ms: number)", "ecma5"),
new QMLTernCompletion("Error", "fn(message: string)", "ecma5"),
new QMLTernCompletion("EvalError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("Function", "fn(body: string) -> fn()", "ecma5"),
new QMLTernCompletion("Infinity", "number", "ecma5"), new QMLTernCompletion("JSON", "JSON", "ecma5"),
new QMLTernCompletion("Math", "Math", "ecma5"), new QMLTernCompletion("NaN", "number", "ecma5"),
new QMLTernCompletion("Number", "fn(value: ?) -> number", "ecma5"),
new QMLTernCompletion("Object", "fn()", "ecma5"),
new QMLTernCompletion("RangeError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("ReferenceError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("RegExp", "fn(source: string, flags?: string)", "ecma5"),
new QMLTernCompletion("String", "fn(value: ?) -> string", "ecma5"),
new QMLTernCompletion("SyntaxError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("TypeError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("URIError", "fn(message: string)", "ecma5"));
}
@Test
public void testCompletions6() throws Throwable {
if (analyzer == null) {
return;
}
getCompletions("Window {\n\ttest: {\n\t\t|\n\t}\n}",
new QMLTernCompletion("decodeURI", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("decodeURIComponent", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("encodeURI", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("encodeURIComponent", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("eval", "fn(code: string)", "ecma5"),
new QMLTernCompletion("isFinite", "fn(value: number) -> bool", "ecma5"),
new QMLTernCompletion("isNaN", "fn(value: number) -> bool", "ecma5"),
new QMLTernCompletion("parseFloat", "fn(string: string) -> number", "ecma5"),
new QMLTernCompletion("parseInt", "fn(string: string, radix?: number) -> number", "ecma5"),
new QMLTernCompletion("undefined", "?", "ecma5"),
new QMLTernCompletion("Array", "fn(size: number)", "ecma5"),
new QMLTernCompletion("Boolean", "fn(value: ?) -> bool", "ecma5"),
new QMLTernCompletion("Date", "fn(ms: number)", "ecma5"),
new QMLTernCompletion("Error", "fn(message: string)", "ecma5"),
new QMLTernCompletion("EvalError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("Function", "fn(body: string) -> fn()", "ecma5"),
new QMLTernCompletion("Infinity", "number", "ecma5"), new QMLTernCompletion("JSON", "JSON", "ecma5"),
new QMLTernCompletion("Math", "Math", "ecma5"), new QMLTernCompletion("NaN", "number", "ecma5"),
new QMLTernCompletion("Number", "fn(value: ?) -> number", "ecma5"),
new QMLTernCompletion("Object", "fn()", "ecma5"),
new QMLTernCompletion("RangeError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("ReferenceError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("RegExp", "fn(source: string, flags?: string)", "ecma5"),
new QMLTernCompletion("String", "fn(value: ?) -> string", "ecma5"),
new QMLTernCompletion("SyntaxError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("TypeError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("URIError", "fn(message: string)", "ecma5"));
}
@Test
public void testCompletions7() throws Throwable {
if (analyzer == null) {
return;
}
getCompletions("Window {\n\tfunction test() {\n\t\t|\n\t}\n}",
new QMLTernCompletion("decodeURI", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("decodeURIComponent", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("encodeURI", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("encodeURIComponent", "fn(uri: string) -> string", "ecma5"),
new QMLTernCompletion("eval", "fn(code: string)", "ecma5"),
new QMLTernCompletion("isFinite", "fn(value: number) -> bool", "ecma5"),
new QMLTernCompletion("isNaN", "fn(value: number) -> bool", "ecma5"),
new QMLTernCompletion("parseFloat", "fn(string: string) -> number", "ecma5"),
new QMLTernCompletion("parseInt", "fn(string: string, radix?: number) -> number", "ecma5"),
new QMLTernCompletion("test", "fn()", "test1.qml"), new QMLTernCompletion("undefined", "?", "ecma5"),
new QMLTernCompletion("Array", "fn(size: number)", "ecma5"),
new QMLTernCompletion("Boolean", "fn(value: ?) -> bool", "ecma5"),
new QMLTernCompletion("Date", "fn(ms: number)", "ecma5"),
new QMLTernCompletion("Error", "fn(message: string)", "ecma5"),
new QMLTernCompletion("EvalError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("Function", "fn(body: string) -> fn()", "ecma5"),
new QMLTernCompletion("Infinity", "number", "ecma5"), new QMLTernCompletion("JSON", "JSON", "ecma5"),
new QMLTernCompletion("Math", "Math", "ecma5"), new QMLTernCompletion("NaN", "number", "ecma5"),
new QMLTernCompletion("Number", "fn(value: ?) -> number", "ecma5"),
new QMLTernCompletion("Object", "fn()", "ecma5"),
new QMLTernCompletion("RangeError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("ReferenceError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("RegExp", "fn(source: string, flags?: string)", "ecma5"),
new QMLTernCompletion("String", "fn(value: ?) -> string", "ecma5"),
new QMLTernCompletion("SyntaxError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("TypeError", "fn(message: string)", "ecma5"),
new QMLTernCompletion("URIError", "fn(message: string)", "ecma5"));
}
}