blob: f0d1477850b60e3f04c42a1045ae997fbe6d99a9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 Obeo.
* 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
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.acceleo.query.ast.test;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.eclipse.acceleo.query.ast.CallType;
import org.eclipse.acceleo.query.ast.Conditional;
import org.eclipse.acceleo.query.ast.Expression;
import org.eclipse.acceleo.query.ast.Lambda;
import org.eclipse.acceleo.query.ast.Let;
import org.eclipse.acceleo.query.parser.AstBuilder;
import org.eclipse.acceleo.query.parser.AstEvaluator;
import org.eclipse.acceleo.query.runtime.CrossReferenceProvider;
import org.eclipse.acceleo.query.runtime.EvaluationResult;
import org.eclipse.acceleo.query.runtime.IQueryEnvironment;
import org.eclipse.acceleo.query.runtime.impl.CrossReferencerToAQL;
import org.eclipse.acceleo.query.runtime.impl.LambdaValue;
import org.eclipse.acceleo.query.runtime.impl.Nothing;
import org.eclipse.acceleo.query.runtime.impl.QueryEnvironment;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.EcoreUtil.CrossReferencer;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class AstEvaluatorTest extends AstBuilder {
private AstEvaluator evaluator;
/**
* This will create the cross referencer that's to be used by the "eInverse" library. It will attempt to
* create the cross referencer on the target's resourceSet. If it is null, we'll then attempt to create
* the cross referencer on the target's resource. When the resource too is null, we'll create the cross
* referencer on the target's root container.
*
* @param target
* Target of the cross referencing.
*/
private CrossReferenceProvider createEInverseCrossreferencer(EObject target) {
Resource res = null;
ResourceSet rs = null;
CrossReferencer crossReferencer;
if (target.eResource() != null) {
res = target.eResource();
}
if (res != null && res.getResourceSet() != null) {
rs = res.getResourceSet();
}
if (rs != null) {
// Manually add the ecore.ecore resource in the list of cross
// referenced notifiers
final Resource ecoreResource = EcorePackage.eINSTANCE.getEClass().eResource();
final Collection<Notifier> notifiers = new ArrayList<Notifier>();
for (Resource crossReferenceResource : rs.getResources()) {
if (!"emtl".equals(crossReferenceResource.getURI().fileExtension())) {
notifiers.add(crossReferenceResource);
}
}
notifiers.add(ecoreResource);
crossReferencer = new CrossReferencer(notifiers) {
/** Default SUID. */
private static final long serialVersionUID = 1L;
// static initializer
{
crossReference();
done();
}
};
} else if (res != null) {
crossReferencer = new CrossReferencer(res) {
/** Default SUID. */
private static final long serialVersionUID = 1L;
// static initializer
{
crossReference();
done();
}
};
} else {
EObject targetObject = EcoreUtil.getRootContainer(target);
crossReferencer = new CrossReferencer(targetObject) {
/** Default SUID. */
private static final long serialVersionUID = 1L;
// static initializer
{
crossReference();
done();
}
};
}
return new CrossReferencerToAQL(crossReferencer);
}
@Before
public void setup() {
IQueryEnvironment environment = new QueryEnvironment(
createEInverseCrossreferencer(EcorePackage.eINSTANCE), Logger.getLogger("AstEvaluatorTest"));
evaluator = new AstEvaluator(environment);
}
@Test
public void testIntLiteral() {
Map<String, Object> varDefinitions = Maps.newHashMap();
assertOKResultEquals(Integer.valueOf(1), evaluator.eval(varDefinitions, integerLiteral(1)));
}
@Test
public void testRealLiteral() {
Map<String, Object> varDefinitions = Maps.newHashMap();
assertOKResultEquals(Double.valueOf(1d), evaluator.eval(varDefinitions, realLiteral(1.0)));
}
@Test
public void testBoolLiteral() {
Map<String, Object> varDefinitions = Maps.newHashMap();
assertOKResultEquals(Boolean.TRUE, evaluator.eval(varDefinitions, booleanLiteral(true)));
assertOKResultEquals(Boolean.FALSE, evaluator.eval(varDefinitions, booleanLiteral(false)));
}
@Test
public void testStringLiteral() {
Map<String, Object> varDefinitions = Maps.newHashMap();
assertOKResultEquals("john doe", evaluator.eval(varDefinitions, stringLiteral("john doe")));
}
@Test
public void testTypeLiteral() {
Map<String, Object> varDefinitions = Maps.newHashMap();
assertOKResultEquals(EcorePackage.Literals.ECLASS, evaluator.eval(varDefinitions,
typeLiteral(EcorePackage.Literals.ECLASS)));
assertOKResultEquals(Integer.class, evaluator.eval(varDefinitions, typeLiteral(Integer.class)));
}
@Test
public void testFeatureAccess() {
Map<String, Object> varDefinitions = Maps.newHashMap();
varDefinitions.put("self", EcorePackage.Literals.ECLASS);
assertOKResultEquals("EClass", evaluator.eval(varDefinitions, featureAccess(varRef("self"), "name")));
EvaluationResult result = evaluator.eval(varDefinitions, featureAccess(varRef("self"),
"eAllSuperTypes"));
assertTrue(result.getResult() instanceof List);
assertEquals(Diagnostic.OK, result.getDiagnostic().getSeverity());
assertTrue(result.getDiagnostic().getChildren().isEmpty());
List<?> listResult = (List<?>)result.getResult();
assertEquals(3, listResult.size());
assertTrue(listResult.contains(EcorePackage.Literals.EMODEL_ELEMENT));
assertTrue(listResult.contains(EcorePackage.Literals.ENAMED_ELEMENT));
assertTrue(listResult.contains(EcorePackage.Literals.ECLASSIFIER));
}
@Test
public void testVarRef() {
Map<String, Object> varDefinitions = Maps.newHashMap();
varDefinitions.put("self", EcorePackage.Literals.ECLASS);
assertOKResultEquals(EcorePackage.Literals.ECLASS, evaluator.eval(varDefinitions, varRef("self")));
}
@Test
public void testCall() {
Map<String, Object> varDefinitions = Maps.newHashMap();
varDefinitions.put("self", EcorePackage.Literals.ECLASS);
EvaluationResult result = evaluator.eval(varDefinitions, callService(CallType.COLLECTIONCALL, "size",
featureAccess(varRef("self"), "eAllSuperTypes")));
assertOKResultEquals(Integer.valueOf(3), result);
}
@Test
public void testLambda() {
Map<String, Object> varDefinitions = Maps.newHashMap();
varDefinitions.put("x", new Integer(1));
Lambda lambda = lambda(varRef("x"));
EvaluationResult value = evaluator.eval(varDefinitions, lambda);
assertTrue(value.getResult() instanceof LambdaValue);
assertEquals(Diagnostic.OK, value.getDiagnostic().getSeverity());
assertTrue(value.getDiagnostic().getChildren().isEmpty());
assertEquals(Integer.valueOf(1), ((LambdaValue)value.getResult()).eval(new Object[0]));
}
@Test
public void testNullLiteral() {
Map<String, Object> varDefinitions = Maps.newHashMap();
assertOKResultEquals(null, evaluator.eval(varDefinitions, nullLiteral()));
}
@Test
@SuppressWarnings("unchecked")
public void testSetInExtensionLiteral() {
Map<String, Object> varDefinitions = Maps.newHashMap();
varDefinitions.put("self", EcorePackage.Literals.ECLASS);
final List<Expression> values = new ArrayList<Expression>();
values.add(varRef("self"));
values.add(varRef("self"));
values.add(booleanLiteral(true));
values.add(booleanLiteral(false));
final EvaluationResult result = evaluator.eval(varDefinitions, setInExtension(values));
assertTrue(result.getResult() instanceof Set);
assertEquals(Diagnostic.OK, result.getDiagnostic().getSeverity());
assertTrue(result.getDiagnostic().getChildren().isEmpty());
Set<Object> setResult = (Set<Object>)result.getResult();
assertEquals(3, setResult.size());
Iterator<Object> it = setResult.iterator();
assertEquals(EcorePackage.Literals.ECLASS, it.next());
assertEquals(Boolean.TRUE, it.next());
assertEquals(Boolean.FALSE, it.next());
assertFalse(it.hasNext());
}
@Test
@SuppressWarnings("unchecked")
public void testSequenceInExtensionLiteral() {
Map<String, Object> varDefinitions = Maps.newHashMap();
varDefinitions.put("self", EcorePackage.Literals.ECLASS);
final List<Expression> values = new ArrayList<Expression>();
values.add(varRef("self"));
values.add(varRef("self"));
values.add(booleanLiteral(true));
values.add(booleanLiteral(false));
final EvaluationResult result = evaluator.eval(varDefinitions, sequenceInExtension(values));
assertTrue(result.getResult() instanceof List);
assertEquals(Diagnostic.OK, result.getDiagnostic().getSeverity());
assertTrue(result.getDiagnostic().getChildren().isEmpty());
List<Object> listResult = (List<Object>)result.getResult();
assertEquals(4, listResult.size());
Iterator<Object> it = listResult.iterator();
assertEquals(EcorePackage.Literals.ECLASS, it.next());
assertEquals(EcorePackage.Literals.ECLASS, it.next());
assertEquals(Boolean.TRUE, it.next());
assertEquals(Boolean.FALSE, it.next());
assertFalse(it.hasNext());
}
/**
* Test that the true branch is properly evaluated when the predicate evaluates to <code>true</code>
*/
@Test
public void testConditionnalTrueBranch() {
Map<String, Object> varDefinitions = Maps.newHashMap();
Conditional conditional = conditional(booleanLiteral(true), stringLiteral("trueBranch"),
stringLiteral("falseBranch"));
assertOKResultEquals("trueBranch", evaluator.eval(varDefinitions, conditional));
}
/**
* Test that the false branch is properly evaluated when the predicate evaluates to <code>false</code>
*/
@Test
public void testConditionnalFalseBranch() {
Map<String, Object> varDefinitions = Maps.newHashMap();
Conditional conditional = conditional(booleanLiteral(false), stringLiteral("trueBranch"),
stringLiteral("falseBranch"));
assertOKResultEquals("falseBranch", evaluator.eval(varDefinitions, conditional));
}
/**
* Test that the result is <code>Nothing</code> when the predicate isn't a boolean
*/
@Test
public void testConditionnalBadPredicate() {
Map<String, Object> varDefinitions = Maps.newHashMap();
Conditional conditional = conditional(stringLiteral("Hey, what's this?!"),
stringLiteral("trueBranch"), stringLiteral("falseBranch"));
final EvaluationResult result = evaluator.eval(varDefinitions, conditional);
assertTrue(result.getResult() instanceof Nothing);
assertEquals(Diagnostic.WARNING, result.getDiagnostic().getSeverity());
assertEquals(1, result.getDiagnostic().getChildren().size());
String message = result.getDiagnostic().getChildren().get(0).getMessage();
assertTrue(message.contains("Conditional"));
assertTrue(message.contains("boolean"));
}
@Test
public void testLetBasic() {
Let let = let(callService(CallType.CALLSERVICE, "concat", varRef("x"), varRef("y")), binding("x",
stringLiteral("prefix")), binding("y", stringLiteral("suffix")));
Map<String, Object> varDefinitions = Maps.newHashMap();
assertOKResultEquals("prefixsuffix", evaluator.eval(varDefinitions, let));
}
@Test
public void testLetArenotRecursive() {
Let let = let(callService(CallType.CALLSERVICE, "concat", varRef("x"), varRef("y")), binding("x",
stringLiteral("prefix")), binding("y", callService(CallType.CALLSERVICE, "concat",
varRef("x"), stringLiteral("end"))));
Map<String, Object> varDefinitions = Maps.newHashMap();
varDefinitions.put("x", "firstx");
assertOKResultEquals("prefixfirstxend", evaluator.eval(varDefinitions, let));
}
@Test
public void testLetWithNothingBound() {
Let let = let(callService(CallType.CALLSERVICE, "concat", varRef("x"), varRef("y")), binding("x",
varRef("prefix")), binding("y", stringLiteral("suffix")));
Map<String, Object> varDefinitions = Maps.newHashMap();
final EvaluationResult result = evaluator.eval(varDefinitions, let);
assertTrue(result.getResult() instanceof Nothing);
assertEquals(Diagnostic.WARNING, result.getDiagnostic().getSeverity());
assertEquals(2, result.getDiagnostic().getChildren().size());
String message1 = result.getDiagnostic().getChildren().get(0).getMessage();
assertTrue(message1.contains("Couldn't find the prefix variable"));
String message2 = result.getDiagnostic().getChildren().get(1).getMessage();
assertTrue(message2.contains("Couldn't find the concat"));
}
@Test
public void testLetWithNothingBody() {
Let let = let(callService(CallType.CALLSERVICE, "concat", varRef("novar"), varRef("y")), binding("x",
stringLiteral("prefix")), binding("y", stringLiteral("suffix")));
Map<String, Object> varDefinitions = Maps.newHashMap();
final EvaluationResult result = evaluator.eval(varDefinitions, let);
assertTrue(result.getResult() instanceof Nothing);
assertEquals(Diagnostic.WARNING, result.getDiagnostic().getSeverity());
assertEquals(2, result.getDiagnostic().getChildren().size());
String message1 = result.getDiagnostic().getChildren().get(0).getMessage();
assertTrue(message1.contains("Couldn't find the novar variable"));
String message2 = result.getDiagnostic().getChildren().get(1).getMessage();
assertTrue(message2.contains("Couldn't find the concat"));
}
private void assertOKResultEquals(Object expected, EvaluationResult result) {
assertEquals(expected, result.getResult());
assertEquals(Diagnostic.OK, result.getDiagnostic().getSeverity());
assertTrue(result.getDiagnostic().getChildren().isEmpty());
}
}