/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.tools.expression.internal.function;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import com.rapidminer.MacroHandler;
import com.rapidminer.example.Attribute;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.example.table.AttributeFactory;
import com.rapidminer.example.table.PolynominalMapping;
import com.rapidminer.example.utils.ExampleSetBuilder;
import com.rapidminer.example.utils.ExampleSets;
import com.rapidminer.tools.Ontology;
import com.rapidminer.tools.expression.ExampleResolver;
import com.rapidminer.tools.expression.Expression;
import com.rapidminer.tools.expression.ExpressionException;
import com.rapidminer.tools.expression.ExpressionType;
import com.rapidminer.tools.expression.MacroResolver;
import com.rapidminer.tools.expression.internal.antlr.AntlrParser;
/**
* Tests the results of {@link AntlrParser#parse(String)} for the eval function.
*
* @author Gisa Schaefer
*
*/
public class AntlrParserEvalTest extends AntlrParserTest {
@Test
public void evalWrongNumberOfArguments() {
try {
getExpressionWithFunctionContext("eval()");
fail();
} catch (ExpressionException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void evalWrongInputType() {
try {
getExpressionWithFunctionContext("eval(2 ,1.5 )");
fail();
} catch (ExpressionException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void multiplyIntsViaEval() {
try {
Expression expression = getExpressionWithFunctionContext("eval(\"3*5\")");
assertEquals(ExpressionType.INTEGER, expression.getExpressionType());
assertEquals(3 * 5, expression.evaluateNumerical(), 1e-15);
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalMissingString() {
try {
Expression expression = getExpressionWithFunctionContext("eval(MISSING_NOMINAL)");
assertEquals(ExpressionType.STRING, expression.getExpressionType());
assertEquals(null, expression.evaluateNominal());
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void multiplyIntsViaEvalToDouble() {
try {
Expression expression = getExpressionWithFunctionContext("eval(\"3*5\",REAL)");
assertEquals(ExpressionType.DOUBLE, expression.getExpressionType());
assertEquals(3 * 5, expression.evaluateNumerical(), 1e-15);
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void multiplyDoublesViaEval() {
try {
Expression expression = getExpressionWithFunctionContext("eval(\"3.0\"+\"*5\")");
assertEquals(ExpressionType.DOUBLE, expression.getExpressionType());
assertEquals(3.0 * 5, expression.evaluateNumerical(), 1e-15);
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void divideIntsViaEvalWithType() {
try {
Expression expression = getExpressionWithFunctionContext("eval(\"4 /2\",REAL)");
assertEquals(ExpressionType.DOUBLE, expression.getExpressionType());
assertEquals(4.0 / 2, expression.evaluateNumerical(), 1e-15);
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void divideDoublesViaEvalWithWrongType() {
try {
getExpressionWithFunctionContext("eval(\"5.0 /2\",INTEGER)");
fail();
} catch (ExpressionException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void evalWithInvalidType() {
try {
getExpressionWithFunctionContext("eval(\"5.0 /2\",\"blup\")");
fail();
} catch (ExpressionException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void moduloIntsViaEvalWithStringType() {
try {
Expression expression = getExpressionWithFunctionContext("eval(\"5 %2\",NOMINAL)");
assertEquals(ExpressionType.STRING, expression.getExpressionType());
assertEquals(5 % 2 + "", expression.evaluateNominal());
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalWithStringTypeMissing() {
try {
Expression expression = getExpressionWithFunctionContext("eval(\"MISSING_NOMINAL\",NOMINAL)");
assertEquals(ExpressionType.STRING, expression.getExpressionType());
assertEquals(null, expression.evaluateNominal());
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalWithStringTypeMissingNumerical() {
try {
Expression expression = getExpressionWithFunctionContext("eval(\"MISSING_NUMERIC\",NOMINAL)");
assertEquals(ExpressionType.STRING, expression.getExpressionType());
assertEquals(null, expression.evaluateNominal());
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalWithStringTypeMissingDate() {
try {
Expression expression = getExpressionWithFunctionContext("eval(\"MISSING_DATE\",NOMINAL)");
assertEquals(ExpressionType.STRING, expression.getExpressionType());
assertEquals(null, expression.evaluateNominal());
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void differentPointOperationsWithNestedEvalFail() {
try {
getExpressionWithFunctionContext("eval(\"4%3 *\"+\"eval(\"+\"5/2\"+\")\")");
fail();
} catch (ExpressionException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void powerIntsEvalWithMacro() {
try {
MacroHandler handler = new MacroHandler(null);
handler.addMacro("my macro", "2^3^2");
MacroResolver resolver = new MacroResolver(handler);
Expression expression = getExpressionWithFunctionsAndMacros("eval(%{my macro})", resolver);
assertEquals(ExpressionType.INTEGER, expression.getExpressionType());
assertEquals(Math.pow(2, Math.pow(3, 2)), expression.evaluateNumerical(), 1e-15);
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void differentPointOperationsWithNestedEval() {
try {
MacroHandler handler = new MacroHandler(null);
handler.addMacro("my macro", "\"5/2\"");
MacroResolver resolver = new MacroResolver(handler);
Expression expression = getExpressionWithFunctionsAndMacros("eval(\"4%3 *\"+\"eval(\"+%{my macro}+\")\")",
resolver);
assertEquals(ExpressionType.DOUBLE, expression.getExpressionType());
assertEquals(4 % 3 * 5 / 2.0, expression.evaluateNumerical(), 1e-15);
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalAttributeWithoutSecond() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
getExpressionWithFunctionsAndExamples("eval([nominal])", resolver);
fail();
} catch (ExpressionException e) {
assertNotNull(e.getMessage());
}
}
private ExampleSet makeExampleSet() {
List<Attribute> attributes = new LinkedList<>();
Map<Integer, String> nominalMapping = new HashMap<>();
nominalMapping.put(0, "contains(\"a\", \"b\")");
nominalMapping.put(1, "concat(\"a\", \"b\")");
Attribute nominal = AttributeFactory.createAttribute("nominal", Ontology.NOMINAL);
nominal.setMapping(new PolynominalMapping(nominalMapping));
attributes.add(nominal);
attributes.add(AttributeFactory.createAttribute("numerical", Ontology.NUMERICAL));
attributes.add(AttributeFactory.createAttribute("integer", Ontology.INTEGER));
ExampleSetBuilder builder = ExampleSets.from(attributes);
double[] data = { 0, 1.5, 5 };
builder.addRow(data);
data = new double[] { 1, 3.0, Double.NaN };
builder.addRow(data);
return builder.build();
}
@Test
public void evalAttributeWithSecond() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamples("eval(\"3*\"+[integer],INTEGER)", resolver);
resolver.bind(exampleSet.getExample(0));
assertEquals(ExpressionType.INTEGER, expression.getExpressionType());
assertEquals(3 * 5, expression.evaluateNumerical(), 1e-15);
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalAttributeWithSecondToDouble() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamples("eval(\"3*\"+[integer],REAL)", resolver);
resolver.bind(exampleSet.getExample(0));
assertEquals(ExpressionType.DOUBLE, expression.getExpressionType());
assertEquals(3.0 * 5, expression.evaluateNumerical(), 1e-15);
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalAttributeWithSecondToString() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamples("eval(\"3*\"+[integer],NOMINAL)", resolver);
resolver.bind(exampleSet.getExample(0));
assertEquals(ExpressionType.STRING, expression.getExpressionType());
assertEquals(3 * 5 + "", expression.evaluateNominal());
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalAttributeWithSecondNotConstant() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
getExpressionWithFunctionsAndExamples("eval(\"3*\"+[integer],[nominal])", resolver);
fail();
} catch (ExpressionException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void evalAttributeWithSecondToStringMissing() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamples("eval(\"MISSING_DATE\"+[integer],NOMINAL)",
resolver);
resolver.bind(exampleSet.getExample(1));
assertEquals(ExpressionType.STRING, expression.getExpressionType());
assertEquals(null, expression.evaluateNominal());
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalAttributeWithSecondToStringMissingBoth() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamples("eval(MISSING+[integer],NOMINAL)", resolver);
resolver.bind(exampleSet.getExample(1));
assertEquals(ExpressionType.STRING, expression.getExpressionType());
assertEquals(null, expression.evaluateNominal());
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalAttributeWithSecondToDate() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamples("eval(\"3*\"+[integer],DATE)", resolver);
assertEquals(ExpressionType.DATE, expression.getExpressionType());
resolver.bind(exampleSet.getExample(0));
expression.evaluateDate();
fail();
} catch (ExpressionException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void evalRealAttributeWithSecondToDouble() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamples("eval(\"3*\"+[numerical],REAL)", resolver);
resolver.bind(exampleSet.getExample(0));
assertEquals(ExpressionType.DOUBLE, expression.getExpressionType());
assertEquals(3 * 1.5, expression.evaluateNumerical(), 1e-15);
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalRealAttributeWithSecondToInteger() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamples("eval(\"3*\"+[numerical],INTEGER)", resolver);
assertEquals(ExpressionType.INTEGER, expression.getExpressionType());
resolver.bind(exampleSet.getExample(0));
expression.evaluateNumerical();
fail();
} catch (ExpressionException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void evalStringAttributeWithSecond() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamples("eval([nominal],NOMINAL)", resolver);
assertEquals(ExpressionType.STRING, expression.getExpressionType());
resolver.bind(exampleSet.getExample(0));
assertEquals("false", expression.evaluateNominal());
resolver.bind(exampleSet.getExample(1));
assertEquals("ab", expression.evaluateNominal());
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalBooleanAttributeWithSecond() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamples("eval([nominal],BINOMINAL)", resolver);
assertEquals(ExpressionType.BOOLEAN, expression.getExpressionType());
resolver.bind(exampleSet.getExample(0));
assertEquals(false, expression.evaluateBoolean());
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void evalAttributeFromString() {
try {
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamples("eval(\"integer\")", resolver);
assertEquals(ExpressionType.INTEGER, expression.getExpressionType());
resolver.bind(exampleSet.getExample(0));
assertEquals(5, expression.evaluateNumerical(), 1e-15);
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void attributeFromMacro() {
try {
MacroHandler handler = new MacroHandler(null);
handler.addMacro("attribute", "integer");
MacroResolver macroResolver = new MacroResolver(handler);
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamplesAndMacros("eval(%{attribute})", resolver,
macroResolver);
assertEquals(ExpressionType.INTEGER, expression.getExpressionType());
resolver.bind(exampleSet.getExample(0));
assertEquals(5, expression.evaluateNumerical(), 1e-15);
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
@Test
public void attributeFromMacroWithType() {
try {
MacroHandler handler = new MacroHandler(null);
handler.addMacro("attribute", "integer");
MacroResolver macroResolver = new MacroResolver(handler);
ExampleSet exampleSet = makeExampleSet();
ExampleResolver resolver = new ExampleResolver(exampleSet);
Expression expression = getExpressionWithFunctionsAndExamplesAndMacros("eval(%{attribute},NOMINAL)", resolver,
macroResolver);
assertEquals(ExpressionType.STRING, expression.getExpressionType());
resolver.bind(exampleSet.getExample(0));
assertEquals("5", expression.evaluateNominal());
} catch (ExpressionException e) {
fail(e.getMessage());
}
}
}