diff --git a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/IParameterProvider.java b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/IParameterProvider.java index 91a0e64c6..cac3491dc 100644 --- a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/IParameterProvider.java +++ b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/IParameterProvider.java @@ -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 params, IExpectation expectation, + boolean ignore); // void acceptTestClass(Class clazz); } diff --git a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/InjectParameter.java b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/InjectParameter.java new file mode 100644 index 000000000..e3e6f6045 --- /dev/null +++ b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/InjectParameter.java @@ -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 ""; +} diff --git a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/Offset.java b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/Offset.java new file mode 100644 index 000000000..77c5d2a13 --- /dev/null +++ b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/Offset.java @@ -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 getEStructuralFeatureByOffset() { + return getEStructuralFeatureByOffset(Predicates. alwaysTrue()); + } + + public Pair getEStructuralFeatureByOffset(Predicate 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 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); + } +} diff --git a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/OffsetHelper.java b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/OffsetHelper.java deleted file mode 100644 index b23503bc1..000000000 --- a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/OffsetHelper.java +++ /dev/null @@ -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 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 getEStructuralFeatureByOffset() { - return getEStructuralFeatureByOffset(Predicates. alwaysTrue()); - } - - public Pair getEStructuralFeatureByOffset(Predicate 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; - } - } - -} diff --git a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/Parameter.java b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/ParameterSyntax.java similarity index 92% rename from plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/Parameter.java rename to plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/ParameterSyntax.java index b529b91ab..2ba97078e 100644 --- a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/Parameter.java +++ b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/ParameterSyntax.java @@ -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 ""; } diff --git a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunner.java b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunner.java index bacfc8ab8..a0eab088f 100644 --- a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunner.java +++ b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunner.java @@ -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 { protected boolean ignore; protected int index = -1; protected String methodName; - protected Object[][] params; + protected Multimap params; protected ResourceRunner runner; protected String title; @@ -169,7 +171,7 @@ public class ParameterizedXtextRunner extends ParentRunner { return methodName; } - public Object[][] getParams() { + public Multimap getParams() { return params; } @@ -181,7 +183,7 @@ public class ParameterizedXtextRunner extends ParentRunner { 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 params, IExpectation expectation, boolean ignore) { this.runner = runner; this.title = title; @@ -209,7 +211,8 @@ public class ParameterizedXtextRunner extends ParentRunner { 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 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 { 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 alternatives = Lists.newArrayList(); - for (Object[] params : allParams) { - List 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 params) { + List 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 alternatives = Lists.newArrayList(); + // for (Object[] params : allParams) { + // List 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); diff --git a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/XpectParameterProvider.java b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/XpectParameterProvider.java index 0d5b027a2..ff153a6ea 100644 --- a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/XpectParameterProvider.java +++ b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/parameterized/XpectParameterProvider.java @@ -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. 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 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 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. singleton(value); } - return value; + return Collections. singleton(value); } - protected Object[][] createParams(XtextResource res, Map params) { - Object[] params1 = new Object[] { res, params }; - Object[] params2 = new Object[] { res }; - return new Object[][] { params1, params2 }; + protected Multimap getDefaultParams(XtextResource res, int offset) { + Multimap 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 params = Maps.newLinkedHashMap(); + Multimap params = HashMultimap.create(); Wrapper expectation = new Wrapper(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 params) { + protected int parseXpectParams(Class testClass, XtextResource res, INode node, String methodName, + final String text, int offset, Multimap 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; diff --git a/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunner.xtext b/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunner.xtext index c487759b5..6f8891f07 100644 --- a/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunner.xtext +++ b/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunner.xtext @@ -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' diff --git a/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunnerTest.java b/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunnerTest.java index dd4ac5100..ff64f12ba 100644 --- a/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunnerTest.java +++ b/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/ParameterizedXtextRunnerTest.java @@ -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 params; - public ParameterizedXtextRunnerTest(XtextResource res, Map 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()); + } + } diff --git a/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/XpectParameterProviderTest.java b/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/XpectParameterProviderTest.java index 7a28b5597..714e2b580 100644 --- a/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/XpectParameterProviderTest.java +++ b/tests/org.eclipse.xtext.junit4.tests/src/org/eclipse/xtext/junit4/parameterized/XpectParameterProviderTest.java @@ -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 params, + IExpectation expectation, boolean ignore) { StringBuilder str = new StringBuilder(); if (ignore) str.append("(ignored) "); if (title != null) str.append("'" + title + "' "); - List p1 = Lists.newArrayList(); - for (Object[] o : params) - { - List 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 p1 = Lists.newArrayList(); + // for (String key : params.keySet()) + // { + // List 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 params, + IExpectation expectation, boolean ignore) { - XtextResource res = (XtextResource) params[0][0]; - @SuppressWarnings("unchecked") - Map map = (Map) params[0][1]; + // XtextResource res = (XtextResource) + // params.get(XpectParameterProvider.PARAM_RESOURCE).iterator().next(); List p2 = Lists.newArrayList(); - String text = res.getParseResult().getRootNode().getText(); - for (Map.Entry e : map.entrySet()) + // String text = res.getParseResult().getRootNode().getText(); + for (Map.Entry 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 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())); }