[ParameterizedXtextRunner] improved compatibility with Xtend

This commit is contained in:
Moritz Eysholdt 2011-10-30 19:54:53 +01:00
parent 3a2cf78f5c
commit a860797a62
10 changed files with 380 additions and 246 deletions

View file

@ -11,6 +11,7 @@ import org.eclipse.emf.common.util.URI;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.util.Strings;
import com.google.common.collect.Multimap;
import com.google.inject.ImplementedBy;
/**
@ -46,7 +47,8 @@ public interface IParameterProvider {
public interface IParameterAcceptor {
void acceptImportURI(URI uri);
void acceptTest(String title, String method, Object[][] params, IExpectation expectation, boolean ignore);
void acceptTest(String title, String method, Multimap<String, Object> params, IExpectation expectation,
boolean ignore);
// void acceptTestClass(Class<?> clazz);
}

View file

@ -0,0 +1,22 @@
/*******************************************************************************
* Copyright (c) 2011 itemis AG (http://www.itemis.eu) 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.xtext.junit4.parameterized;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Moritz Eysholdt - Initial contribution and API
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectParameter {
String value() default "";
}

View file

@ -0,0 +1,123 @@
/*******************************************************************************
* Copyright (c) 2011 itemis AG (http://www.itemis.eu) 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.xtext.junit4.parameterized;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.parsetree.reconstr.impl.NodeIterator;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.util.Tuples;
import org.junit.Assert;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
/**
* @author Moritz Eysholdt - Initial contribution and API
*/
public class Offset {
protected int offset;
protected XtextResource resource;
public Offset(XtextResource resource, int offset) {
super();
this.resource = resource;
this.offset = offset;
}
public EObject getEObject() {
EObject object = NodeModelUtils.findActualSemanticObjectFor(getLeafNodeAtOffset());
Assert.assertNotNull("No EObject found at offset " + offset, object);
return object;
}
public Pair<EObject, EStructuralFeature> getEStructuralFeatureByOffset() {
return getEStructuralFeatureByOffset(Predicates.<EStructuralFeature> alwaysTrue());
}
public Pair<EObject, EStructuralFeature> getEStructuralFeatureByOffset(Predicate<EStructuralFeature> matches) {
INode leaf = getLeafNodeAtOffset();
NodeIterator ni = null;
while (ni == null || ni.hasNext()) {
INode next = ni == null ? leaf : ni.next();
if (ni == null)
ni = new NodeIterator(leaf);
Assignment ass = GrammarUtil.containingAssignment(next.getGrammarElement());
if (ass != null) {
EObject object = NodeModelUtils.findActualSemanticObjectFor(next);
EStructuralFeature feat = object.eClass().getEStructuralFeature(ass.getFeature());
if (feat != null && matches.apply(feat))
return Tuples.create(object, feat);
}
}
Assert.fail("No EStructuralFeature found at offset " + offset);
return null;
}
public Pair<EObject, EStructuralFeature> getEStructuralFeatureByParent() {
INode leaf = getLeafNodeAtOffset();
EObject object = NodeModelUtils.findActualSemanticObjectFor(leaf);
Assert.assertNotNull("No EObject found at offset " + offset, object);
Assignment ass = GrammarUtil.containingAssignment(leaf.getGrammarElement());
while (ass == null && leaf.getParent() != null) {
leaf = leaf.getParent();
ass = GrammarUtil.containingAssignment(leaf.getGrammarElement());
}
Assert.assertNotNull("No Assignment found at offset " + offset, ass);
@SuppressWarnings("null")
EStructuralFeature feature = object.eClass().getEStructuralFeature(ass.getFeature());
return Tuples.create(object, feature);
}
public ILeafNode getLeafNodeAtOffset() {
ILeafNode node = NodeModelUtils.findLeafNodeAtOffset(resource.getParseResult().getRootNode(), offset);
Assert.assertNotNull("No Leaf Node found at offset " + offset, node);
return node;
}
@Override
public int hashCode() {
return offset * (resource != null ? resource.hashCode() : 1);
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass())
return false;
Offset off = (Offset) obj;
return resource == off.resource && offset == off.offset;
}
public int getOffset() {
return offset;
}
public XtextResource getResource() {
return resource;
}
@Override
public String toString() {
if (resource == null)
return "(resource is null)";
if (resource.getParseResult() == null || resource.getParseResult().getRootNode() == null)
return "(resource hs no parse result)";
String text = resource.getParseResult().getRootNode().getText();
if (offset < 0 || offset > text.length())
return "(offset out of range)";
int from = Math.max(0, offset - 5);
int to = Math.min(text.length(), offset + 5);
return text.substring(from, offset) + "!" + text.substring(offset, to);
}
}

View file

@ -1,100 +0,0 @@
/*******************************************************************************
* Copyright (c) 2011 itemis AG (http://www.itemis.eu) 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.xtext.junit4.parameterized;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.parsetree.reconstr.impl.NodeIterator;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.util.Tuples;
import org.junit.Assert;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
/**
* @author Moritz Eysholdt - Initial contribution and API
*/
public class OffsetHelper {
public Offset at(XtextResource resource, int offset) {
return new Offset(resource, offset);
}
public Offset at(XtextResource resource, String offset) {
return at(resource, Integer.valueOf(offset));
}
public static class Offset {
protected int offset;
protected XtextResource resource;
public Offset(XtextResource resource, int offset) {
super();
this.resource = resource;
this.offset = offset;
}
public EObject getEObject() {
EObject object = NodeModelUtils.findActualSemanticObjectFor(getLeafNodeAtOffset());
Assert.assertNotNull("No EObject found at offset " + offset, object);
return object;
}
public Pair<EObject, EStructuralFeature> getEStructuralFeatureByParent() {
INode leaf = getLeafNodeAtOffset();
EObject object = NodeModelUtils.findActualSemanticObjectFor(leaf);
Assert.assertNotNull("No EObject found at offset " + offset, object);
Assignment ass = GrammarUtil.containingAssignment(leaf.getGrammarElement());
while (ass == null && leaf.getParent() != null) {
leaf = leaf.getParent();
ass = GrammarUtil.containingAssignment(leaf.getGrammarElement());
}
Assert.assertNotNull("No Assignment found at offset " + offset, ass);
@SuppressWarnings("null")
EStructuralFeature feature = object.eClass().getEStructuralFeature(ass.getFeature());
return Tuples.create(object, feature);
}
public Pair<EObject, EStructuralFeature> getEStructuralFeatureByOffset() {
return getEStructuralFeatureByOffset(Predicates.<EStructuralFeature> alwaysTrue());
}
public Pair<EObject, EStructuralFeature> getEStructuralFeatureByOffset(Predicate<EStructuralFeature> matches) {
INode leaf = getLeafNodeAtOffset();
NodeIterator ni = null;
while (ni == null || ni.hasNext()) {
INode next = ni == null ? leaf : ni.next();
if (ni == null)
ni = new NodeIterator(leaf);
Assignment ass = GrammarUtil.containingAssignment(next.getGrammarElement());
if (ass != null) {
EObject object = NodeModelUtils.findActualSemanticObjectFor(next);
EStructuralFeature feat = object.eClass().getEStructuralFeature(ass.getFeature());
if (feat != null && matches.apply(feat))
return Tuples.create(object, feat);
}
}
Assert.fail("No EStructuralFeature found at offset " + offset);
return null;
}
public ILeafNode getLeafNodeAtOffset() {
ILeafNode node = NodeModelUtils.findLeafNodeAtOffset(resource.getParseResult().getRootNode(), offset);
Assert.assertNotNull("No Leaf Node found at offset " + offset, node);
return node;
}
}
}

View file

@ -17,7 +17,7 @@ import java.lang.annotation.Target;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Parameter {
String syntax() default "";
public @interface ParameterSyntax {
String value() default "";
}

View file

@ -11,6 +11,7 @@ import static org.eclipse.xtext.util.Exceptions.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@ -48,6 +49,7 @@ import org.junit.runners.model.TestClass;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
/**
@ -131,7 +133,7 @@ public class ParameterizedXtextRunner extends ParentRunner<ResourceRunner> {
protected boolean ignore;
protected int index = -1;
protected String methodName;
protected Object[][] params;
protected Multimap<String, Object> params;
protected ResourceRunner runner;
protected String title;
@ -169,7 +171,7 @@ public class ParameterizedXtextRunner extends ParentRunner<ResourceRunner> {
return methodName;
}
public Object[][] getParams() {
public Multimap<String, Object> getParams() {
return params;
}
@ -181,7 +183,7 @@ public class ParameterizedXtextRunner extends ParentRunner<ResourceRunner> {
return runner.clazz.getJavaClass();
}
public void init(ResourceRunner runner, String title, String method, Object[][] params,
public void init(ResourceRunner runner, String title, String method, Multimap<String, Object> params,
IExpectation expectation, boolean ignore) {
this.runner = runner;
this.title = title;
@ -209,7 +211,8 @@ public class ParameterizedXtextRunner extends ParentRunner<ResourceRunner> {
resourceSet.getResource(uri, true);
}
public void acceptTest(String title, String method, Object[][] params, IExpectation expectation, boolean ignore) {
public void acceptTest(String title, String method, Multimap<String, Object> params, IExpectation expectation,
boolean ignore) {
ParameterSetRunner runner = injectorProvider.getInjector().getInstance(ParameterSetRunner.class);
runner.init(this, title, method, params, expectation, ignore);
parameterSets.add(runner);
@ -380,35 +383,68 @@ public class ParameterizedXtextRunner extends ParentRunner<ResourceRunner> {
return result;
}
protected Object newTestInstance(Object[][] allParams) throws IllegalArgumentException, InstantiationException,
IllegalAccessException, InvocationTargetException {
for (Object[] params : allParams)
ROOT: for (Constructor<?> candidate : getTestClass().getJavaClass().getConstructors())
if (candidate.getParameterTypes().length == params.length) {
for (int i = 0; i < params.length; i++)
if (params[i] != null
&& !ReflectionUtil.getObjectType(candidate.getParameterTypes()[i])
.isInstance(params[i]))
continue ROOT;
return candidate.newInstance(params);
}
List<String> alternatives = Lists.newArrayList();
for (Object[] params : allParams) {
List<String> types = Lists.newArrayList();
for (Object p : params)
types.add(p == null ? "?" : p.getClass().getName());
alternatives.add(Joiner.on(", ").join(types));
}
throw new RuntimeException("No valid constructor found in class " + getTestClass().getJavaClass().getName()
+ " for types " + Joiner.on(" or ").join(alternatives));
protected Object newTestInstance() throws SecurityException, NoSuchMethodException, IllegalArgumentException,
InstantiationException, IllegalAccessException, InvocationTargetException {
Constructor<?> constructor = getTestClass().getJavaClass().getConstructor();
return constructor.newInstance();
}
protected void injectParameters(Object test, Multimap<String, Object> params) {
List<Field> fields = Lists.newArrayList();
Class<?> clazz = test.getClass();
while (clazz != null && clazz != Object.class) {
fields.addAll(Lists.newArrayList(clazz.getDeclaredFields()));
clazz = clazz.getSuperclass();
}
for (Field field : fields) {
InjectParameter annotation = field.getAnnotation(InjectParameter.class);
if (annotation != null) {
String name = Strings.isEmpty(annotation.value()) ? field.getName() : annotation.value();
Class<?> fieldType = ReflectionUtil.getObjectType(field.getType());
for (Object value : params.get(name))
if (fieldType.isInstance(value)) {
field.setAccessible(true);
try {
field.set(test, value);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
}
}
}
}
// protected Object newTestInstance(Object[][] allParams) throws IllegalArgumentException, InstantiationException,
// IllegalAccessException, InvocationTargetException {
// for (Object[] params : allParams)
// ROOT: for (Constructor<?> candidate : getTestClass().getJavaClass().getConstructors())
// if (candidate.getParameterTypes().length == params.length) {
// for (int i = 0; i < params.length; i++)
// if (params[i] != null
// && !ReflectionUtil.getObjectType(candidate.getParameterTypes()[i])
// .isInstance(params[i]))
// continue ROOT;
// return candidate.newInstance(params);
// }
// List<String> alternatives = Lists.newArrayList();
// for (Object[] params : allParams) {
// List<String> types = Lists.newArrayList();
// for (Object p : params)
// types.add(p == null ? "?" : p.getClass().getName());
// alternatives.add(Joiner.on(", ").join(types));
// }
// throw new RuntimeException("No valid constructor found in class " + getTestClass().getJavaClass().getName()
// + " for types " + Joiner.on(" or ").join(alternatives));
// }
protected void runChild(ParameterSetRunner ps) throws Throwable {
MethodWithExpectation method = findTestMethod(ps.getMethdoName());
Object test = newTestInstance(ps.getParams());
Object test = newTestInstance();
if (ps.getInjectorProvider() instanceof IRegistryConfigurator)
((IRegistryConfigurator) ps.getInjectorProvider()).setupRegistry();
try {
injectParameters(test, ps.getParams());
ps.getInjectorProvider().getInjector().injectMembers(test);
Object result = method.getMethod().invoke(test);
method.getValidator().validate(ps.getResource(), ps.getExpectation(), result);

View file

@ -9,10 +9,10 @@ package org.eclipse.xtext.junit4.parameterized;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -35,7 +35,9 @@ import org.eclipse.xtext.util.formallang.StringProduction.ElementType;
import org.eclipse.xtext.util.formallang.StringProduction.ProdElement;
import org.junit.Test;
import com.google.common.collect.Maps;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
/**
* @author Moritz Eysholdt - Initial contribution and API
@ -166,7 +168,8 @@ public class XpectParameterProvider implements IParameterProvider {
}
}
public final static String OFFSET = "offset";
public final static String PARAM_OFFSET = "offset";
public final static String PARAM_RESOURCE = "resource";
protected static final Pattern WS = Pattern.compile("^[\\s]+");
@ -184,15 +187,13 @@ public class XpectParameterProvider implements IParameterProvider {
for (Method meth : testClass.getMethods()) {
if (Modifier.isPublic(meth.getModifiers()) && !Modifier.isStatic(meth.getModifiers())) {
Test annotation = meth.getAnnotation(Test.class);
if (annotation != null) {
Object[][] params = createParams(res, Collections.<String, String> emptyMap());
acceptor.acceptTest(null, meth.getName(), params, null, false);
}
if (annotation != null)
acceptor.acceptTest(null, meth.getName(), getDefaultParams(res, 0), null, false);
}
}
}
protected String convertValue(INode ctx, int offset, Token token, String value) {
protected Iterable<Object> convertValue(XtextResource res, INode ctx, int offset, Token token, String value) {
switch (token) {
case OFFSET:
int add = value.indexOf('!');
@ -202,23 +203,37 @@ public class XpectParameterProvider implements IParameterProvider {
add = 0;
String text = ctx.getRootNode().getText();
int result = text.indexOf(value, offset);
if (result >= 0)
return String.valueOf(result + add);
else
if (result >= 0) {
int off = result + add;
return Lists.newArrayList(off, new Offset(res, off));
} else
throw new RuntimeException("OFFSET '" + value + "' not found");
case ID:
case INT:
List<Object> r = Lists.newArrayList();
try {
r.add(Integer.valueOf(value));
} catch (NumberFormatException e) {
}
try {
r.add(new BigInteger(value));
} catch (NumberFormatException e) {
}
r.add(value);
return r;
case ID:
case STRING:
case TEXT:
return value;
return Collections.<Object> singleton(value);
}
return value;
return Collections.<Object> singleton(value);
}
protected Object[][] createParams(XtextResource res, Map<String, String> params) {
Object[] params1 = new Object[] { res, params };
Object[] params2 = new Object[] { res };
return new Object[][] { params1, params2 };
protected Multimap<String, Object> getDefaultParams(XtextResource res, int offset) {
Multimap<String, Object> result = HashMultimap.create();
result.put(PARAM_RESOURCE, res);
result.put(PARAM_OFFSET, offset);
result.put(PARAM_OFFSET, new Offset(res, offset));
return result;
}
protected String getIndentation(INode ctx, int offset) {
@ -254,9 +269,9 @@ public class XpectParameterProvider implements IParameterProvider {
protected String getParameterSyntax(Class<?> testClass, String methodName) {
try {
Method method = testClass.getMethod(methodName);
Parameter annotation = method.getAnnotation(Parameter.class);
ParameterSyntax annotation = method.getAnnotation(ParameterSyntax.class);
if (annotation != null)
return annotation.syntax();
return annotation.value();
} catch (SecurityException e) {
Exceptions.throwUncheckedException(e);
} catch (NoSuchMethodException e) {
@ -330,17 +345,17 @@ public class XpectParameterProvider implements IParameterProvider {
protected int parseXpect(Class<?> testClass, XtextResource res, INode ctx, String text, String method, int offset,
IParameterAcceptor acceptor, boolean ignore) {
int newOffset;
Map<String, String> params = Maps.newLinkedHashMap();
Multimap<String, Object> params = HashMultimap.create();
Wrapper<Expectation> expectation = new Wrapper<Expectation>(null);
offset = skipWhitespace(text, offset);
if ((newOffset = parseXpectParams(testClass, ctx, method, text, offset, params)) >= 0)
if ((newOffset = parseXpectParams(testClass, res, ctx, method, text, offset, params)) >= 0)
offset = newOffset;
offset = skipWhitespace(text, offset);
if ((newOffset = parseXpectSLExpectation(ctx, text, offset, expectation)) >= 0)
offset = newOffset;
else if ((newOffset = parseXpectMLExpectation(ctx, text, offset, expectation)) >= 0)
offset = newOffset;
acceptor.acceptTest(null, method, createParams(res, params), expectation.get(), ignore);
acceptor.acceptTest(null, method, params, expectation.get(), ignore);
return offset;
}
@ -377,10 +392,10 @@ public class XpectParameterProvider implements IParameterProvider {
return -1;
}
protected int parseXpectParams(Class<?> testClass, INode node, String methodName, final String text, int offset,
Map<String, String> params) {
protected int parseXpectParams(Class<?> testClass, XtextResource res, INode node, String methodName,
final String text, int offset, Multimap<String, Object> params) {
int semanticOffset = getOffsetOfNextSemanticNode(node);
params.put(OFFSET, String.valueOf(semanticOffset));
params.putAll(getDefaultParams(res, semanticOffset));
String paramSyntax = getParameterSyntax(testClass, methodName);
if (Strings.isEmpty(paramSyntax))
return -1;
@ -421,9 +436,12 @@ public class XpectParameterProvider implements IParameterProvider {
});
if (trace != null && !trace.isEmpty()) {
for (BacktrackItem item : trace)
if (item.token != null && item.token.getName() != null)
params.put(item.token.getName(),
convertValue(node, semanticOffset, Token.valueOf(item.token.getValue()), item.value));
if (item.token != null && item.token.getName() != null) {
String key = item.token.getName();
params.removeAll(key);
params.putAll(key,
convertValue(res, node, semanticOffset, Token.valueOf(item.token.getValue()), item.value));
}
return trace.get(trace.size() - 1).offset;
}
return -1;

View file

@ -23,7 +23,8 @@ import "http://www.eclipse.org/emf/2002/Ecore" as ecore
xxx yyy zzz
--- */
// XPECT select from fo!o to b!az --> o='val' bar='val1' b
// XPECT select1 from fo!o to b!az --> o='val' bar='val1' b
// XPECT select2 from fo!o to b!az --> o='val' bar='val1' b
Root:
foo='val' bar='val1' baz='xxx'

View file

@ -3,8 +3,7 @@ package org.eclipse.xtext.junit4.parameterized;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Map;
import junit.framework.Assert;
import org.eclipse.xtext.IGrammarAccess;
import org.eclipse.xtext.junit4.InjectWith;
@ -24,14 +23,20 @@ import com.google.inject.Inject;
public class ParameterizedXtextRunnerTest
{
@InjectParameter
private XtextResource resource;
private Map<String, String> params;
public ParameterizedXtextRunnerTest(XtextResource res, Map<String, String> params)
{
this.resource = res;
this.params = params;
}
@InjectParameter
private int from;
@InjectParameter
private int to;
@InjectParameter("from")
private Offset fromObj;
@InjectParameter("to")
private Offset toObj;
@Inject
IGrammarAccess injected;
@ -62,7 +67,7 @@ public class ParameterizedXtextRunnerTest
assertEquals(2, xpectString);
assertEquals(1, xpectCsv);
assertEquals(1, xpectLines);
assertEquals(1, xpectSelect);
assertEquals(2, xpectSelect);
}
@Xpect
@ -94,14 +99,23 @@ public class ParameterizedXtextRunnerTest
}
@XpectString
@Parameter(syntax = "'from' from=OFFSET 'to' to=OFFSET")
public String select()
@ParameterSyntax("'from' from=OFFSET 'to' to=OFFSET")
public String select1()
{
xpectSelect++;
String text = resource.getParseResult().getRootNode().getText();
int from = Integer.parseInt(params.get("from"));
int to = Integer.parseInt(params.get("to"));
return text.substring(from, to);
}
@XpectString
@ParameterSyntax("'from' from=OFFSET 'to' to=OFFSET")
public String select2()
{
xpectSelect++;
Assert.assertNotNull(fromObj);
Assert.assertNotNull(toObj);
String text = resource.getParseResult().getRootNode().getText();
return text.substring(fromObj.getOffset(), toObj.getOffset());
}
}

View file

@ -1,12 +1,12 @@
package org.eclipse.xtext.junit4.parameterized;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import junit.framework.Assert;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.junit4.InjectWith;
import org.eclipse.xtext.junit4.XtextRunner;
@ -21,6 +21,7 @@ import org.junit.runner.RunWith;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;
@RunWith(XtextRunner.class)
@ -33,12 +34,12 @@ public class XpectParameterProviderTest
{
}
@Parameter(syntax = "'at' myOffset=OFFSET")
@ParameterSyntax("'at' myOffset=OFFSET")
public void offsetMeth()
{
}
@Parameter(syntax = "('text' myText=TEXT)? ('int' myInt=INT)? ('string' myString=STRING)? ('id' myId=ID)?")
@ParameterSyntax("('text' myText=TEXT)? ('int' myInt=INT)? ('string' myString=STRING)? ('id' myId=ID)?")
public void optionalMeth()
{
}
@ -71,34 +72,34 @@ public class XpectParameterProviderTest
result.add("import " + uri);
}
public void acceptTest(String title, String method, Object[][] params, IExpectation expectation,
boolean ignore)
public void acceptTest(String title, String method, Multimap<String, Object> params,
IExpectation expectation, boolean ignore)
{
StringBuilder str = new StringBuilder();
if (ignore)
str.append("(ignored) ");
if (title != null)
str.append("'" + title + "' ");
List<String> p1 = Lists.newArrayList();
for (Object[] o : params)
{
List<String> p2 = Lists.newArrayList();
for (Object x : o)
{
if (x == null)
p2.add("null");
else if (x instanceof Resource)
p2.add("Res");
else if (x instanceof Map<?, ?>)
p2.add("Map");
else if (x instanceof Integer)
p2.add("Int");
else
p2.add(x.getClass().getSimpleName());
}
p1.add(Joiner.on(", ").join(p2));
}
str.append(method + "(" + Joiner.on(" | ").join(p1) + ")");
// List<String> p1 = Lists.newArrayList();
// for (String key : params.keySet())
// {
// List<String> p2 = Lists.newArrayList();
// for (Object x : params.get(key))
// {
// if (x == null)
// p2.add("null");
// else if (x instanceof Resource)
// p2.add("Res");
// else if (x instanceof Map<?, ?>)
// p2.add("Map");
// else if (x instanceof Integer)
// p2.add("Int");
// else
// p2.add(x.getClass().getSimpleName());
// }
// p1.add(key + "=" + Joiner.on("|").join(p2));
// }
str.append(method /* + "(" + Joiner.on(", ").join(p1) + ")" */);
if (expectation != null)
str.append(" --> " + expectation.getExpectation().replace("\n", "\\n"));
result.add(str.toString());
@ -130,26 +131,36 @@ public class XpectParameterProviderTest
{
}
public void acceptTest(String title, String method, Object[][] params, IExpectation expectation,
boolean ignore)
public void acceptTest(String title, String method, Multimap<String, Object> params,
IExpectation expectation, boolean ignore)
{
XtextResource res = (XtextResource) params[0][0];
@SuppressWarnings("unchecked")
Map<String, String> map = (Map<String, String>) params[0][1];
// XtextResource res = (XtextResource)
// params.get(XpectParameterProvider.PARAM_RESOURCE).iterator().next();
List<String> p2 = Lists.newArrayList();
String text = res.getParseResult().getRootNode().getText();
for (Map.Entry<String, String> e : map.entrySet())
// String text = res.getParseResult().getRootNode().getText();
for (Map.Entry<String, Object> e : params.entries())
{
if (e.getKey().toLowerCase().contains("offset"))
/*
* if (e.getKey().toLowerCase().contains("offset") &&
* e.getValue() instanceof Integer) { int offs = (Integer)
* e.getValue(); String val = "'" + text.substring(offs - 3,
* offs) + "!" + text.substring(offs, offs + 3) + "'";
* p2.add(e.getKey() + " at " + val.replace("\n", "\\n")); }
* else
*/if (e.getKey().equals(XpectParameterProvider.PARAM_RESOURCE))
p2.add(e.getKey());
else
{
int offs = Integer.parseInt(e.getValue());
String val = "'" + text.substring(offs - 3, offs) + "!" + text.substring(offs, offs + 3) + "'";
p2.add(e.getKey() + " at " + val.replace("\n", "\\n"));
} else
p2.add(e.getKey() + " = " + e.getValue());
String val = e.getValue().toString().replace("\n", "\\n");
if (val.contains(" ") || val.contains("\t"))
val = "'" + val + "'";
p2.add(e.getKey() + "=" + val);
}
}
Collections.sort(p2);
result.add(method + "(" + Joiner.on(", ").join(p2) + ")");
}
});
return Joiner.on("\n").join(result);
} catch (Exception e)
@ -178,7 +189,8 @@ public class XpectParameterProviderTest
{
}
public void acceptTest(String title, String method, Object[][] params, IExpectation expectation, boolean ignore)
public void acceptTest(String title, String method, Multimap<String, Object> params, IExpectation expectation,
boolean ignore)
{
String replace;
if (expectation.getIndentation() != null)
@ -200,14 +212,14 @@ public class XpectParameterProviderTest
public void xpectSL()
{
String model = "// XPECT meth";
Assert.assertEquals("meth(Res, Map | Res)", parse(model));
Assert.assertEquals("meth", parse(model));
}
@Test
public void xpectML()
{
String model = "/* XPECT meth */";
Assert.assertEquals("meth(Res, Map | Res)", parse(model));
Assert.assertEquals("meth", parse(model));
}
@Test
@ -215,7 +227,7 @@ public class XpectParameterProviderTest
{
String model = "// XPECT meth -->\n";
String actual = parse(model);
Assert.assertEquals("meth(Res, Map | Res) --> ", actual);
Assert.assertEquals("meth --> ", actual);
Assert.assertEquals("// XPECT meth -->xxx\n", expectation(model));
}
@ -224,7 +236,7 @@ public class XpectParameterProviderTest
{
String model = "// XPECT meth --> \n";
String actual = parse(model);
Assert.assertEquals("meth(Res, Map | Res) --> ", actual);
Assert.assertEquals("meth --> ", actual);
Assert.assertEquals("// XPECT meth --> xxx\n", expectation(model));
}
@ -233,7 +245,7 @@ public class XpectParameterProviderTest
{
String model = "// XPECT meth --> \n";
String actual = parse(model);
Assert.assertEquals("meth(Res, Map | Res) --> ", actual);
Assert.assertEquals("meth --> ", actual);
Assert.assertEquals("// XPECT meth --> xxx\n", expectation(model));
}
@ -241,7 +253,7 @@ public class XpectParameterProviderTest
public void xpectSLExpectation1()
{
String model = "// XPECT meth -->exp\n";
Assert.assertEquals("meth(Res, Map | Res) --> exp", parse(model));
Assert.assertEquals("meth --> exp", parse(model));
Assert.assertEquals("// XPECT meth -->xxx\n", expectation(model));
}
@ -249,7 +261,7 @@ public class XpectParameterProviderTest
public void xpectSLExpectation2()
{
String model = "// XPECT meth --> exp\n";
Assert.assertEquals("meth(Res, Map | Res) --> exp", parse(model));
Assert.assertEquals("meth --> exp", parse(model));
Assert.assertEquals("// XPECT meth --> xxx\n", expectation(model));
}
@ -257,7 +269,7 @@ public class XpectParameterProviderTest
public void xpectSLExpectation3()
{
String model = "// XPECT meth --> exp \n";
Assert.assertEquals("meth(Res, Map | Res) --> exp ", parse(model));
Assert.assertEquals("meth --> exp ", parse(model));
Assert.assertEquals("// XPECT meth --> xxx\n", expectation(model));
}
@ -265,7 +277,7 @@ public class XpectParameterProviderTest
public void xpectMLExpectation0()
{
String model = "/* XPECT meth -->\n*/";
Assert.assertEquals("meth(Res, Map | Res) --> ", parse(model));
Assert.assertEquals("meth --> ", parse(model));
Assert.assertEquals("/* XPECT meth -->xxx\n*/", expectation(model));
}
@ -273,7 +285,7 @@ public class XpectParameterProviderTest
public void xpectMLExpectation01()
{
String model = "/* XPECT meth --> \n*/";
Assert.assertEquals("meth(Res, Map | Res) --> ", parse(model));
Assert.assertEquals("meth --> ", parse(model));
Assert.assertEquals("/* XPECT meth --> xxx\n*/", expectation(model));
}
@ -281,7 +293,7 @@ public class XpectParameterProviderTest
public void xpectMLExpectation02()
{
String model = "/* XPECT meth --> \n*/";
Assert.assertEquals("meth(Res, Map | Res) --> ", parse(model));
Assert.assertEquals("meth --> ", parse(model));
Assert.assertEquals("/* XPECT meth --> xxx\n*/", expectation(model));
}
@ -289,7 +301,7 @@ public class XpectParameterProviderTest
public void xpectMLExpectation1()
{
String model = "/* XPECT meth -->exp\n*/";
Assert.assertEquals("meth(Res, Map | Res) --> exp", parse(model));
Assert.assertEquals("meth --> exp", parse(model));
Assert.assertEquals("/* XPECT meth -->xxx\n*/", expectation(model));
}
@ -297,7 +309,7 @@ public class XpectParameterProviderTest
public void xpectMLExpectation2()
{
String model = "/* XPECT meth --> exp\n*/";
Assert.assertEquals("meth(Res, Map | Res) --> exp", parse(model));
Assert.assertEquals("meth --> exp", parse(model));
Assert.assertEquals("/* XPECT meth --> xxx\n*/", expectation(model));
}
@ -305,7 +317,7 @@ public class XpectParameterProviderTest
public void xpectMLExpectation3()
{
String model = "/* XPECT meth --> exp \n*/";
Assert.assertEquals("meth(Res, Map | Res) --> exp ", parse(model));
Assert.assertEquals("meth --> exp ", parse(model));
Assert.assertEquals("/* XPECT meth --> xxx\n*/", expectation(model));
}
@ -313,7 +325,7 @@ public class XpectParameterProviderTest
public void xpectMLExpectation4()
{
String model = "\n/* XPECT meth ---\nexp\n---*/\n";
Assert.assertEquals("meth(Res, Map | Res) --> exp", parse(model));
Assert.assertEquals("meth --> exp", parse(model));
Assert.assertEquals("\n/* XPECT meth ---\nxxx\n---*/\n", expectation(model));
}
@ -326,7 +338,7 @@ public class XpectParameterProviderTest
model.append("--- */\n");
StringBuilder parsed = new StringBuilder();
parsed.append("meth(Res, Map | Res) --> exp");
parsed.append("meth --> exp");
StringBuilder replaced = new StringBuilder();
replaced.append("/* XPECT meth ---\n");
@ -346,7 +358,7 @@ public class XpectParameterProviderTest
model.append(" --- */\n");
StringBuilder parsed = new StringBuilder();
parsed.append("meth(Res, Map | Res) --> exp");
parsed.append("meth --> exp");
StringBuilder replaced = new StringBuilder();
replaced.append(" /* XPECT meth ---\n");
@ -366,7 +378,7 @@ public class XpectParameterProviderTest
model.append("\t--- */\n");
StringBuilder parsed = new StringBuilder();
parsed.append("meth(Res, Map | Res) --> exp");
parsed.append("meth --> exp");
StringBuilder replaced = new StringBuilder();
replaced.append("\t/* XPECT meth ---\n");
@ -388,7 +400,7 @@ public class XpectParameterProviderTest
model.append("\t --- */\n");
StringBuilder parsed = new StringBuilder();
parsed.append("meth(Res, Map | Res) --> tree {\\n node\\n }");
parsed.append("meth --> tree {\\n node\\n }");
StringBuilder replaced = new StringBuilder();
replaced.append("\t /* XPECT meth ---\n");
@ -403,73 +415,79 @@ public class XpectParameterProviderTest
public void xpectMLOffsetParameter1()
{
String model = "/* XPECT offsetMeth at foo --> exp \n*/ Bar: val='foo';";
Assert.assertEquals("offsetMeth(offset at '*/ !Bar', myOffset at 'l='!foo')", params(model));
Assert.assertEquals("offsetMeth(myOffset=154, myOffset=val='!foo';, offset=' \\n*/ !Bar: ', offset=144, resource)",
params(model));
}
@Test
public void xpectMLOffsetParameter2()
{
String model = "/* XPECT offsetMeth at fo!o --> exp \n*/ Bar: val='foo';";
Assert.assertEquals("offsetMeth(offset at '*/ !Bar', myOffset at ''fo!o';')", params(model));
Assert.assertEquals(
"offsetMeth(myOffset='l='fo!o';\\n ', myOffset=157, offset=' \\n*/ !Bar: ', offset=145, resource)",
params(model));
}
@Test
public void xpectSLParameterText()
{
String model = "// XPECT optionalMeth text foo";
Assert.assertEquals("optionalMeth(offset at 'o\\n !foo', myText = foo)", params(model));
Assert.assertEquals("optionalMeth(myText=foo, offset='foo\\n !foo:v', offset=136, resource)", params(model));
}
@Test
public void xpectSLParameterString()
{
String model = "// XPECT optionalMeth string 'foo'";
Assert.assertEquals("optionalMeth(offset at ''\\n !foo', myString = foo)", params(model));
Assert.assertEquals("optionalMeth(myString=foo, offset='oo'\\n !foo:v', offset=140, resource)", params(model));
}
@Test
public void xpectSLParameterInt()
{
String model = "// XPECT optionalMeth int 123";
Assert.assertEquals("optionalMeth(offset at '3\\n !foo', myInt = 123)", params(model));
Assert.assertEquals("optionalMeth(myInt=123, myInt=123, myInt=123, offset='123\\n !foo:v', offset=135, resource)",
params(model));
}
@Test
public void xpectSLParameterId()
{
String model = "// XPECT optionalMeth id foo";
Assert.assertEquals("optionalMeth(offset at 'o\\n !foo', myId = foo)", params(model));
Assert.assertEquals("optionalMeth(myId=foo, offset='foo\\n !foo:v', offset=134, resource)", params(model));
}
@Test
public void xpectSLParameterAll()
{
String model = "// XPECT optionalMeth text abc int 123 string 'str' id foo";
Assert.assertEquals("optionalMeth(offset at 'o\\n !foo', myText = abc, myInt = 123, myString = str, myId = foo)",
params(model));
Assert
.assertEquals(
"optionalMeth(myId=foo, myInt=123, myInt=123, myInt=123, myString=str, myText=abc, offset='foo\\n !foo:v', offset=164, resource)",
params(model));
}
@Test
public void xpectSLParameterDefault()
{
String model = "// XPECT meth";
Assert.assertEquals("meth(offset at 'h\\n !foo')", params(model));
Assert.assertEquals("meth(offset='eth\\n !foo:v', offset=119, resource)", params(model));
}
@Test
public void xpectSLParameterWithExp()
{
String model = "// XPECT optionalMeth text abc --> exp\n";
Assert.assertEquals("optionalMeth(Res, Map | Res) --> exp", parse(model));
Assert.assertEquals("optionalMeth(offset at '\\n\\n !foo', myText = abc)", params(model));
Assert.assertEquals("optionalMeth --> exp", parse(model));
Assert.assertEquals("optionalMeth(myText=abc, offset='xp\\n\\n !foo:v', offset=145, resource)", params(model));
}
@Test
public void xpectMLParameterWithExp()
{
String model = "/* XPECT optionalMeth text abc ---\n exp\n--- */";
Assert.assertEquals("optionalMeth(Res, Map | Res) --> exp", parse(model));
Assert.assertEquals("optionalMeth(offset at '/\\n !foo', myText = abc)", params(model));
Assert.assertEquals("optionalMeth --> exp", parse(model));
Assert.assertEquals("optionalMeth(myText=abc, offset=' */\\n !foo:v', offset=152, resource)", params(model));
}
@Test
@ -490,9 +508,9 @@ public class XpectParameterProviderTest
StringBuilder parsed = new StringBuilder();
parsed.append("import foo.ext\n");
parsed.append("meth(Res, Map | Res)\n");
parsed.append("meth(Res, Map | Res)\n");
parsed.append("optionalMeth(Res, Map | Res) --> exp");
parsed.append("meth\n");
parsed.append("meth\n");
parsed.append("optionalMeth --> exp");
Assert.assertEquals(parsed.toString(), parse(model.toString()));
}