/** * Copyright (c) 2011 committers of YAKINDU 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 * Contributors: * committers of YAKINDU - initial API and implementation * */ package org.yakindu.sct.model.stext.test; import static org.junit.Assert.assertTrue; import org.eclipse.xtext.junit4.InjectWith; import org.eclipse.xtext.junit4.XtextRunner; import org.junit.Test; import org.junit.runner.RunWith; import org.yakindu.base.expressions.expressions.Expression; import org.yakindu.base.types.inferrer.ITypeSystemInferrer; import org.yakindu.sct.model.stext.stext.EventRaisingExpression; import org.yakindu.sct.model.stext.stext.VariableDefinition; import org.yakindu.sct.model.stext.test.util.AbstractTypeInferrerTest; import org.yakindu.sct.model.stext.test.util.STextInjectorProvider; import org.yakindu.sct.model.stext.test.util.STextTestScopeProvider; /** * @author andreas muelder - Initial contribution and API * @author axel terfloth - additional tests * @author Alexander Nyßen - Adopted to changes in type system * */ @RunWith(XtextRunner.class) @InjectWith(STextInjectorProvider.class) public class TypeInferrerTest extends AbstractTypeInferrerTest { // Unary @Test public void testNumericalUnaryExpressionSuccess() { // int assertTrue(isIntegerType(inferType("1"))); assertTrue(isIntegerType(inferType("0x0F"))); assertTrue(isIntegerType(inferType("-1"))); assertTrue(isIntegerType(inferType("0"))); assertTrue(isIntegerType(inferType("intVar"))); // real assertTrue(isRealType(inferType("1.0"))); assertTrue(isRealType(inferType("-1.0"))); assertTrue(isRealType(inferType("0.0"))); assertTrue(isRealType(inferType("realVar"))); // string assertTrue(isStringType(inferType("'42'"))); assertTrue(isStringType(inferType("stringVar"))); // boolean assertTrue(isBooleanType(inferType("true"))); assertTrue(isBooleanType(inferType("false"))); assertTrue(isBooleanType(inferType("boolVar"))); assertTrue(isBooleanType(inferType("boolEvent"))); // tilde assertTrue(isIntegerType(inferType(" ~3"))); } @Test public void testNumericalUnaryExpressionFailure() { expectIssue(inferType("~true"), "Bitwise operator '~' may only be applied on integer types, not on boolean."); expectIssue(inferType("~9.0"), "Bitwise operator '~' may only be applied on integer types, not on real."); expectIssue(inferType("~stringVar"), "Bitwise operator '~' may only be applied on integer types, not on string."); } // AddSubtract @Test public void testNumericalAddSubtractExpression() { // add assertTrue(isIntegerType(inferTypeForExpression("1+2", internalScope()))); assertTrue(isIntegerType(inferType("1 + 2"))); assertTrue(isIntegerType(inferType("1 + 0x0F"))); assertTrue(isIntegerType(inferType("0x0F + 0x0F"))); assertTrue(isIntegerType(inferType("intVar + 0x0F"))); assertTrue(isIntegerType(inferType("intVar + 2"))); assertTrue(isRealType(inferType("1.1 + 2"))); assertTrue(isRealType(inferType("2 + 1.0"))); assertTrue(isRealType(inferType("1 + 2 + 3.0"))); // subtract assertTrue(isIntegerType(inferType("1 - 2"))); assertTrue(isIntegerType(inferType("0x0F - 2"))); assertTrue(isIntegerType(inferType("0x0F - 0x0F"))); assertTrue(isIntegerType(inferType("0x0F- intVar"))); assertTrue(isIntegerType(inferType("intVar - 2"))); assertTrue(isRealType(inferType("1.0 - 2"))); assertTrue(isRealType(inferType("2 - 1.0"))); assertTrue(isRealType(inferType("realVar - 1.0"))); assertTrue(isRealType(inferType("1 - 2 - 3.0"))); } @Test public void testNumericalAddSubtractExpressionFailure() { // add expectIssue(inferType("true + 5"), "Arithmetic operator '+' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("false + 5"), "Arithmetic operator '+' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("5 + false"), "Arithmetic operator '+' may only be applied on numeric types, not on integer and boolean."); expectIssue(inferType("true + (3 * 5)"), "Arithmetic operator '+' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("(3 * 5) + true"), "Arithmetic operator '+' may only be applied on numeric types, not on integer and boolean."); expectIssue(inferType("3.0 + true"), "Arithmetic operator '+' may only be applied on numeric types, not on real and boolean."); expectIssue(inferType("3.0 + 'string'"), "Arithmetic operator '+' may only be applied on numeric types, not on real and string."); expectIssue(inferType("intVar + 'string'"), "Arithmetic operator '+' may only be applied on numeric types, not on integer and string."); // subtract expectIssue(inferType("true - 5"), "Arithmetic operator '-' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("false - 5"), "Arithmetic operator '-' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("5 - false"), "Arithmetic operator '-' may only be applied on numeric types, not on integer and boolean."); expectIssue(inferType("true - (3 * 5)"), "Arithmetic operator '-' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("(3 * 5) - true"), "Arithmetic operator '-' may only be applied on numeric types, not on integer and boolean."); expectIssue(inferType("3.0 - true"), "Arithmetic operator '-' may only be applied on numeric types, not on real and boolean."); expectIssue(inferType("3.0 - 'string'"), "Arithmetic operator '-' may only be applied on numeric types, not on real and string."); expectIssue(inferType("intVar - 'string'"), "Arithmetic operator '-' may only be applied on numeric types, not on integer and string."); } // multiply @Test public void testMultiplyDivideExpressionSuccess() { // multiply // integer assertTrue(isIntegerType(inferType("1 * 2"))); assertTrue(isIntegerType(inferType("1 * 0x0F"))); assertTrue(isIntegerType(inferType("0x0F * intVar"))); // real assertTrue(isRealType(inferType("intVar * realVar"))); assertTrue(isRealType(inferType("1.0 * 2"))); assertTrue(isRealType(inferType("2 * 1.0"))); assertTrue(isRealType(inferType("1 * 2 * 3.0"))); // divide // integer assertTrue(isIntegerType(inferType("1 / 2"))); assertTrue(isIntegerType(inferType("1 / intVar"))); assertTrue(isIntegerType(inferType("1 / 0x0F"))); assertTrue(isIntegerType(inferType("0x0F / 0x0F"))); assertTrue(isIntegerType(inferType("intVar / 0x0F"))); // real assertTrue(isRealType(inferType("1.0 / 2"))); assertTrue(isRealType(inferType("2 / 1.0"))); assertTrue(isRealType(inferType("1 / 2 / 3.0"))); // modulo // integer assertTrue(isIntegerType(inferType("1 % 2"))); assertTrue(isIntegerType(inferType("1 % 0x0F"))); assertTrue(isIntegerType(inferType("0x0F % 0x0F"))); assertTrue(isIntegerType(inferType("intVar % 0x0F"))); // real assertTrue(isRealType(inferType("1.0 % 2"))); assertTrue(isRealType(inferType("2 % 1.0"))); assertTrue(isRealType(inferType("2 % realVar"))); assertTrue(isRealType(inferType("1 % 2 % 3.0"))); } @Test public void testMultiplyDivideExpressionFailure() { // multiply expectIssue(inferType("true * 5"), "Arithmetic operator '*' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("5 * false"), "Arithmetic operator '*' may only be applied on numeric types, not on integer and boolean."); expectIssue(inferType("true * (3 - 5)"), "Arithmetic operator '*' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("(3 + 5) * true"), "Arithmetic operator '*' may only be applied on numeric types, not on integer and boolean."); expectIssue(inferType("3.0 * true"), "Arithmetic operator '*' may only be applied on numeric types, not on real and boolean."); expectIssue(inferType("3.0 * 'string'"), "Arithmetic operator '*' may only be applied on numeric types, not on real and string."); expectIssue(inferType("realVar * 'string'"), "Arithmetic operator '*' may only be applied on numeric types, not on real and string."); // divide expectIssue(inferType("true / 5"), "Arithmetic operator '/' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("false / 5"), "Arithmetic operator '/' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("5 / false"), "Arithmetic operator '/' may only be applied on numeric types, not on integer and boolean."); expectIssue(inferType("true / (3 - 5)"), "Arithmetic operator '/' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("(3 + 5) / true"), "Arithmetic operator '/' may only be applied on numeric types, not on integer and boolean."); expectIssue(inferType("3.0 / true"), "Arithmetic operator '/' may only be applied on numeric types, not on real and boolean."); expectIssue(inferType("3.0 / 'string'"), "Arithmetic operator '/' may only be applied on numeric types, not on real and string."); expectIssue(inferType("realVar / stringVar"), "Arithmetic operator '/' may only be applied on numeric types, not on real and string."); // mod expectIssue(inferType("true % 5"), "Arithmetic operator '%' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("false % 5"), "Arithmetic operator '%' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("5 % false"), "Arithmetic operator '%' may only be applied on numeric types, not on integer and boolean."); expectIssue(inferType("true % (3 - 5)"), "Arithmetic operator '%' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("(3 + 5) % true"), "Arithmetic operator '%' may only be applied on numeric types, not on integer and boolean."); expectIssue(inferType("3.0 % true"), "Arithmetic operator '%' may only be applied on numeric types, not on real and boolean."); expectIssue(inferType("3.0 % 'string'"), "Arithmetic operator '%' may only be applied on numeric types, not on real and string."); expectIssue(inferType("3.0 % stringVar"), "Arithmetic operator '%' may only be applied on numeric types, not on real and string."); expectIssue(inferType("realVar % stringVar"), "Arithmetic operator '%' may only be applied on numeric types, not on real and string."); } // LogicalAndExpression @Test public void testLogicalAndExpressionSuccess() { assertTrue(isBooleanType(inferType("true && false"))); assertTrue(isBooleanType(inferType("true && boolVar"))); assertTrue(isBooleanType(inferType("boolEvent && valueof(boolEvent)"))); assertTrue(isBooleanType(inferType("boolEvent && intEvent"))); // intEvent // is a // shortcut // for // isRaised(intEvent), // thus // of // boolean // type assertTrue(isBooleanType(inferType("boolEvent && boolEvent"))); } @Test public void testLogicalAndExpressionFailure() { expectIssue(inferType("true && 5"), "Logical operator '&&' may only be applied on boolean types, not on boolean and integer."); expectIssue(inferType("5 && false"), "Logical operator '&&' may only be applied on boolean types, not on integer and boolean."); expectIssue(inferType("3.0 && true"), "Logical operator '&&' may only be applied on boolean types, not on real and boolean."); expectIssue(inferType("5 && boolEvent"), "Logical operator '&&' may only be applied on boolean types, not on integer and boolean."); expectIssue(inferType("true && 'string'"), "Logical operator '&&' may only be applied on boolean types, not on boolean and string."); expectIssue(inferType("true && 1.2"), "Logical operator '&&' may only be applied on boolean types, not on boolean and real."); } // LogicalOrExpression @Test public void testLogicalOrExpressionSuccess() { assertTrue(isBooleanType(inferType("true || false"))); assertTrue(isBooleanType(inferType("true || boolVar"))); assertTrue(isBooleanType(inferType("boolEvent || valueof(boolEvent)"))); assertTrue(isBooleanType(inferType("boolEvent || intEvent"))); // intEvent // is a // shortcut // for // isRaised(intEvent), // thus // of // boolean // type assertTrue(isBooleanType(inferType("boolEvent || boolEvent"))); } @Test public void testLogicalOrExpressionFailure() { expectIssue(inferType("false || 5"), "Logical operator '||' may only be applied on boolean types, not on boolean and integer."); expectIssue(inferType("5 || true"), "Logical operator '||' may only be applied on boolean types, not on integer and boolean."); expectIssue(inferType("3.0 || true"), "Logical operator '||' may only be applied on boolean types, not on real and boolean."); expectIssue(inferType("5 || boolEvent"), "Logical operator '||' may only be applied on boolean types, not on integer and boolean."); expectIssue(inferType("5 || 'string'"), "Logical operator '||' may only be applied on boolean types, not on integer and string."); expectIssue(inferType("5 || 1.2"), "Logical operator '||' may only be applied on boolean types, not on integer and real."); } // LogicalNotExpression @Test public void testLogicalNotExpressionSuccess() { assertTrue(isBooleanType(inferType("!true"))); assertTrue(isBooleanType(inferType("!boolVar"))); assertTrue(isBooleanType(inferType("!valueof(boolEvent)"))); assertTrue(isBooleanType(inferType("!intEvent"))); // intEvent is a // shortcut for // isRaised(intEvent), // thus of boolean // type assertTrue(isBooleanType(inferType("!boolEvent"))); } @Test public void testLogicalNotExpressionFailure() { expectIssue(inferType("!3"), "Logical operator '!' may only be applied on boolean types, not on integer."); expectIssue(inferType("!1.2"), "Logical operator '!' may only be applied on boolean types, not on real."); expectIssue(inferType("!'Test'"), "Logical operator '!' may only be applied on boolean types, not on string."); } // LogicalRelation @Test public void testLogicalRelationExpressionSuccess() { // smaller assertTrue(isBooleanType(inferType("5 < 3"))); assertTrue(isBooleanType(inferType("5.0 < 3"))); assertTrue(isBooleanType(inferType("5.0 < intVar"))); assertTrue(isBooleanType(inferType("5.0 < valueof(intEvent)"))); // smallerEqual assertTrue(isBooleanType(inferType("5 <= 3"))); assertTrue(isBooleanType(inferType("5.0 <= 3"))); assertTrue(isBooleanType(inferType("5.0 <= intVar"))); assertTrue(isBooleanType(inferType("5.0 <= valueof(intEvent)"))); // greater assertTrue(isBooleanType(inferType("5 > 3"))); assertTrue(isBooleanType(inferType("5.0 > 3"))); assertTrue(isBooleanType(inferType("5.0 > intVar"))); assertTrue(isBooleanType(inferType("5.0 > valueof(intEvent)"))); // greaterEqual assertTrue(isBooleanType(inferType("5 >= 3"))); assertTrue(isBooleanType(inferType("5.0 >= 3"))); assertTrue(isBooleanType(inferType("5.0 >= intVar"))); assertTrue(isBooleanType(inferType("5.0 >= valueof(intEvent)"))); // equal assertTrue(isBooleanType(inferType("5 == 3"))); assertTrue(isBooleanType(inferType("'string' == 'string'"))); assertTrue(isBooleanType(inferType("5.0 == 3"))); assertTrue(isBooleanType(inferType("true == boolVar"))); assertTrue(isBooleanType(inferType("true == boolEvent"))); assertTrue(isBooleanType(inferType("true == valueof(boolEvent)"))); // not equal assertTrue(isBooleanType(inferType("5 != 3"))); assertTrue(isBooleanType(inferType("'string' != 'string'"))); assertTrue(isBooleanType(inferType("5.0 != 3"))); assertTrue(isBooleanType(inferType("true != boolVar"))); assertTrue(isBooleanType(inferType("true != boolEvent"))); assertTrue(isBooleanType(inferType("true != valueof(boolEvent)"))); } @Test public void testLogicalRelationExpressionFailure() { // smaller expectIssue(inferType("3.0 < true"), "Comparison operator '<' may only be applied on compatible types, not on real and boolean."); expectIssue(inferType("'string' < 5"), "Comparison operator '<' may only be applied on compatible types, not on string and integer."); expectIssue(inferType("1.0 < false"), "Comparison operator '<' may only be applied on compatible types, not on real and boolean."); expectIssue(inferType("1.0 < boolEvent"), "Comparison operator '<' may only be applied on compatible types, not on real and boolean."); expectIssue( // intEvent is a shortcut for isRaised(intEvent), thus of // boolean type inferType("5 < intEvent"), "Comparison operator '<' may only be applied on compatible types, not on integer and boolean."); // smallerEqual expectIssue(inferType("3.0 <= true"), "Comparison operator '<=' may only be applied on compatible types, not on real and boolean."); expectIssue(inferType("'string' <= 5"), "Comparison operator '<=' may only be applied on compatible types, not on string and integer."); expectIssue(inferType("1.0 <= false"), "Comparison operator '<=' may only be applied on compatible types, not on real and boolean."); expectIssue(inferType("1.0 <= boolEvent"), "Comparison operator '<=' may only be applied on compatible types, not on real and boolean."); expectIssue( // intEvent is a shortcut for isRaised(intEvent), thus of // boolean type inferType("5 <= intEvent"), "Comparison operator '<=' may only be applied on compatible types, not on integer and boolean."); // greater expectIssue(inferType("3.0 > true"), "Comparison operator '>' may only be applied on compatible types, not on real and boolean."); expectIssue(inferType("'string' > 5"), "Comparison operator '>' may only be applied on compatible types, not on string and integer."); expectIssue(inferType("1.0 > false"), "Comparison operator '>' may only be applied on compatible types, not on real and boolean."); expectIssue( // intEvent is a shortcut for isRaised(intEvent), thus of // boolean type inferType("5 <= intEvent"), "Comparison operator '<=' may only be applied on compatible types, not on integer and boolean."); // greaterEqual expectIssue(inferType("3.0 >= true"), "Comparison operator '>=' may only be applied on compatible types, not on real and boolean."); expectIssue(inferType("'string' >= 5"), "Comparison operator '>=' may only be applied on compatible types, not on string and integer."); expectIssue(inferType("1.0 >= false"), "Comparison operator '>=' may only be applied on compatible types, not on real and boolean."); expectIssue( // intEvent is a shortcut for isRaised(intEvent), thus of // boolean type inferType("5 >= intEvent"), "Comparison operator '>=' may only be applied on compatible types, not on integer and boolean."); // equal expectIssue(inferType("3.0 == true"), "Comparison operator '==' may only be applied on compatible types, not on real and boolean."); expectIssue(inferType("'string' == 5"), "Comparison operator '==' may only be applied on compatible types, not on string and integer."); expectIssue(inferType("1.0 == false"), "Comparison operator '==' may only be applied on compatible types, not on real and boolean."); expectIssue( // intEvent is a shortcut for isRaised(intEvent), thus of // boolean type inferType("5 == intEvent"), "Comparison operator '==' may only be applied on compatible types, not on integer and boolean."); // not equal expectIssue(inferType("3.0 != true"), "Comparison operator '!=' may only be applied on compatible types, not on real and boolean."); expectIssue(inferType("'string' != 5"), "Comparison operator '!=' may only be applied on compatible types, not on string and integer."); expectIssue(inferType("1.0 != false"), "Comparison operator '!=' may only be applied on compatible types, not on real and boolean."); expectIssue(inferType("intVar != 'string'"), "Comparison operator '!=' may only be applied on compatible types, not on integer and string."); expectIssue( // intEvent is a shortcut for isRaised(intEvent), thus of // boolean type inferType("5 != intEvent"), "Comparison operator '!=' may only be applied on compatible types, not on integer and boolean."); } @Test public void testAssignmentExpressionSuccess() { // assignment without operator // integer assertTrue(isIntegerType(inferType("intVar = 5 * 3"))); assertTrue(isIntegerType(inferType("intVar = 0x0F * 3"))); assertTrue(isIntegerType(inferType("intVar = intVar * 0x0F"))); assertTrue(isIntegerType(inferType("ABC.intVar = 42"))); // boolean assertTrue(isBooleanType(inferType("boolVar = true || false"))); assertTrue(isBooleanType(inferType("boolVar = boolEvent"))); // string assertTrue(isStringType(inferType("stringVar = 'string'"))); // real assertTrue(isRealType(inferType("realVar = 2.0 - 7"))); // assignment with operator assertTrue(isIntegerType(inferType("intVar += 2"))); assertTrue(isIntegerType(inferType("intVar -= 7"))); assertTrue(isIntegerType(inferType("intVar *= 25"))); assertTrue(isIntegerType(inferType("intVar /= 2"))); assertTrue(isIntegerType(inferType("intVar %= 5"))); // bitwise assertTrue(isIntegerType(inferType("intVar &= 12"))); assertTrue(isIntegerType(inferType("intVar |= 25"))); assertTrue(isIntegerType(inferType("intVar ^= 6"))); assertTrue(isIntegerType(inferType("intVar <<= 215"))); assertTrue(isIntegerType(inferType("intVar >>= 215"))); } @Test public void testAssignmentExpressionFailure() { // integer and real expectIssue(inferType("intVar += 2.0"), "Assignment operator '+=' may only be applied on compatible types, not on integer and real."); expectIssue(inferType("intVar -= 2.0"), "Assignment operator '-=' may only be applied on compatible types, not on integer and real."); expectIssue(inferType("intVar /= 2.0"), "Assignment operator '/=' may only be applied on compatible types, not on integer and real."); expectIssue(inferType("intVar *= 2.0"), "Assignment operator '*=' may only be applied on compatible types, not on integer and real."); expectIssue(inferType("intVar = true"), "Assignment operator '=' may only be applied on compatible types, not on integer and boolean."); // integer and boolean expectIssue(inferType("intVar = boolVar"), "Assignment operator '=' may only be applied on compatible types, not on integer and boolean."); expectIssue(inferType("intVar &= boolVar"), "Assignment operator '&=' may only be applied on compatible types, not on integer and boolean."); expectIssue(inferType("intVar |= boolVar"), "Assignment operator '|=' may only be applied on compatible types, not on integer and boolean."); expectIssue(inferType("intVar ^= boolVar"), "Assignment operator '^=' may only be applied on compatible types, not on integer and boolean."); expectIssue(inferType("intVar >>= boolVar"), "Assignment operator '>>=' may only be applied on compatible types, not on integer and boolean."); expectIssue(inferType("intVar <<= boolVar"), "Assignment operator '<<=' may only be applied on compatible types, not on integer and boolean."); // integer and string expectIssue(inferType("intVar &= 'string'"), "Assignment operator '&=' may only be applied on compatible types, not on integer and string."); expectIssue(inferType("intVar |= 'string'"), "Assignment operator '|=' may only be applied on compatible types, not on integer and string."); expectIssue(inferType("intVar ^= 'string'"), "Assignment operator '^=' may only be applied on compatible types, not on integer and string."); expectIssue(inferType("intVar >>= 'string'"), "Assignment operator '>>=' may only be applied on compatible types, not on integer and string."); expectIssue(inferType("intVar <<= 'string'"), "Assignment operator '<<=' may only be applied on compatible types, not on integer and string."); } /** * the {@link STextTestScopeProvider} adds a dummy state named 'chart.r1.A' * to the Scope. */ @Test public void testActiveStateReferenceExpressionSuccess() throws Exception { assertTrue(isBooleanType(inferType("active(chart.r1.A)"))); assertTrue(isBooleanType(inferType("!active(chart.r1.A)"))); assertTrue(isBooleanType(inferType("true || active(chart.r1.A)"))); assertTrue(isBooleanType(inferType("active(chart.r1.A) && false"))); assertTrue(isBooleanType(inferType("boolVar = active(chart.r1.A)"))); } @Test public void testActiveStateReferenceExpressionFailure() throws Exception { expectIssue(inferType("active(chart.r1.A) + 1"), "Arithmetic operator '+' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("active(chart.r1.A) - 1"), "Arithmetic operator '-' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("active(chart.r1.A) * 1"), "Arithmetic operator '*' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("active(chart.r1.A) / 1"), "Arithmetic operator '/' may only be applied on numeric types, not on boolean and integer."); expectIssue(inferType("active(chart.r1.A) % true"), "Arithmetic operator '%' may only be applied on numeric types, not on boolean and boolean."); expectIssue(inferType("active(chart.r1.A) && intVar"), "Logical operator '&&' may only be applied on boolean types, not on boolean and integer."); expectIssue(inferType("active(chart.r1.A) || stringVar"), "Logical operator '||' may only be applied on boolean types, not on boolean and string."); expectIssue(inferType("active(chart.r1.A) || !stringVar"), "Logical operator '!' may only be applied on boolean types, not on string."); } // bitwise @Test public void testBitwiseXorExpressionSuccess() { assertTrue(isIntegerType(inferType(" 5 ^ 3"))); } @Test public void testBitwiseXorExpressionFailure() { expectIssue(inferType("5 ^ true"), "Bitwise operator '^' may only be applied on integer types, not on integer and boolean."); expectIssue(inferType("5 ^ 1.0"), "Bitwise operator '^' may only be applied on integer types, not on integer and real."); expectIssue(inferType("5 ^ 'stringVar'"), "Bitwise operator '^' may only be applied on integer types, not on integer and string."); } @Test public void testBitwiseOrExpressionSuccess() { assertTrue(isIntegerType(inferType(" 5 | 3"))); } @Test public void testBitwiseOrExpressionFailure() { expectIssue(inferType("5 | true"), "Bitwise operator '|' may only be applied on integer types, not on integer and boolean."); expectIssue(inferType("5 | 1.0"), "Bitwise operator '|' may only be applied on integer types, not on integer and real."); expectIssue(inferType("5 | 'stringVar'"), "Bitwise operator '|' may only be applied on integer types, not on integer and string."); } @Test public void testBitwiseAndExpressionSuccess() { assertTrue(isIntegerType(inferType(" 5 & 3"))); } @Test public void testBitwiseAndExpressionFailure() { expectIssue(inferType("5 & true"), "Bitwise operator '&' may only be applied on integer types, not on integer and boolean."); expectIssue(inferType("5 & 1.0"), "Bitwise operator '&' may only be applied on integer types, not on integer and real."); expectIssue(inferType("5 & 'stringVar'"), "Bitwise operator '&' may only be applied on integer types, not on integer and string."); } @Test public void testShiftExpressionSuccess() { assertTrue(isIntegerType(inferType("3 << 2"))); assertTrue(isIntegerType(inferType("5 >> 2"))); assertTrue(isIntegerType(inferType("intVar << 4"))); assertTrue(isIntegerType(inferType("intVar >> 4"))); } @Test public void testShiftExpressionFailure() { expectIssue(inferType("5 << true"), "Bitwise operator '<<' may only be applied on integer types, not on integer and boolean."); expectIssue(inferType("5 << 7.0"), "Bitwise operator '<<' may only be applied on integer types, not on integer and real."); expectIssue(inferType("5 << stringVar"), "Bitwise operator '<<' may only be applied on integer types, not on integer and string."); expectIssue(inferType("5 >> true"), "Bitwise operator '>>' may only be applied on integer types, not on integer and boolean."); expectIssue(inferType("5 >> 7.0"), "Bitwise operator '>>' may only be applied on integer types, not on integer and real."); expectIssue(inferType("5 >> stringVar"), "Bitwise operator '>>' may only be applied on integer types, not on integer and string."); } @Test // No Expression in SText.xtext public void testComplexExpressionsSuccess() { assertTrue(isBooleanType(inferType("((((3 * intVar) + 5) % 2) > 97) || false"))); assertTrue(isBooleanType(inferType("!true != boolVar && (3 > (realVar * 5 + 3))"))); assertTrue(isIntegerType(inferType("3 * 3 + 7 / (3 * intVar % 8)"))); } @Test public void testEventRaisingExpressionSuccess() { assertTrue(isIntegerType(inferType("raise intEvent : 42", EventRaisingExpression.class.getSimpleName()))); assertTrue(isBooleanType(inferType("raise boolEvent : boolVar", EventRaisingExpression.class.getSimpleName()))); assertTrue(isRealType(inferType("raise realEvent : 2.0 - 3.0", EventRaisingExpression.class.getSimpleName()))); assertTrue(isStringType(inferType("raise stringEvent : 'string'", EventRaisingExpression.class.getSimpleName()))); assertTrue(isVoidType(inferType("raise voidEvent", EventRaisingExpression.class.getSimpleName()))); assertTrue(isIntegerType(inferType("raise ABC.intEvent : 42", EventRaisingExpression.class.getSimpleName()))); } @Test public void testEventRaisingExpressionFailure() { expectIssue(inferType("raise intEvent : true", EventRaisingExpression.class.getSimpleName()), "Cannot assign a value of type boolean to an event of type integer."); expectIssue(inferType("raise intEvent : boolVar", EventRaisingExpression.class.getSimpleName()), "Cannot assign a value of type boolean to an event of type integer."); expectIssue(inferType("raise stringEvent", EventRaisingExpression.class.getSimpleName()), "Need to assign a value to an event of type string."); expectIssue(inferType("raise intEvent : true", EventRaisingExpression.class.getSimpleName()), "Cannot assign a value of type boolean to an event of type integer."); expectIssue(inferType("raise ABC.intEvent", EventRaisingExpression.class.getSimpleName()), "Need to assign a value to an event of type integer."); } @Test public void testEventIsRaisedSuccess() { assertTrue(isBooleanType(inferTypeForExpression("boolVar = intEvent", internalScope()))); assertTrue(isBooleanType(inferTypeForExpression("ABC.boolVar = ABC.intEvent", interfaceScope()))); } @Test // VariableDefinition is a statement, not an expression public void testVariableDefinitionSuccess() { assertTrue(isBooleanType(inferType("var boolVar : boolean = !true", VariableDefinition.class.getSimpleName()))); assertTrue(isIntegerType(inferType("var intVar : integer = 5", VariableDefinition.class.getSimpleName()))); assertTrue(isRealType(inferType("var realVar : real = 0.5", VariableDefinition.class.getSimpleName()))); assertTrue(isRealType(inferType("var realVar : real = 5", VariableDefinition.class.getSimpleName()))); // coercion assertTrue(isStringType(inferType("var stringVar : string = 'test'", VariableDefinition.class.getSimpleName()))); } @Test // VariableDefinition is a statement, not an expression public void testVariableDefinitionFailure() { expectIssue(inferType("var boolVar : boolean = 5", VariableDefinition.class.getSimpleName(), interfaceScope()), "Cannot assign a value of type integer to a variable of type boolean."); expectIssue( inferType("var boolVar : boolean = 0.5", VariableDefinition.class.getSimpleName(), interfaceScope()), "Cannot assign a value of type real to a variable of type boolean."); expectIssue( inferType("var boolVar : boolean = 'text'", VariableDefinition.class.getSimpleName(), interfaceScope()), "Cannot assign a value of type string to a variable of type boolean."); expectIssue( inferType("var intVar : integer = true", VariableDefinition.class.getSimpleName(), interfaceScope()), "Cannot assign a value of type boolean to a variable of type integer."); expectIssue( inferType("var intVar : integer = 0.5", VariableDefinition.class.getSimpleName(), interfaceScope()), "Cannot assign a value of type real to a variable of type integer."); expectIssue( inferType("var intVar : integer = 'text'", VariableDefinition.class.getSimpleName(), interfaceScope()), "Cannot assign a value of type string to a variable of type integer."); expectIssue(inferType("var realVar : real = true", VariableDefinition.class.getSimpleName(), interfaceScope()), "Cannot assign a value of type boolean to a variable of type real."); expectIssue( inferType("var realVar : real = 'text'", VariableDefinition.class.getSimpleName(), interfaceScope()), "Cannot assign a value of type string to a variable of type real."); expectIssue( inferType("var stringVar : string = true", VariableDefinition.class.getSimpleName(), interfaceScope()), "Cannot assign a value of type boolean to a variable of type string."); expectIssue( inferType("var stringVar : string = 5", VariableDefinition.class.getSimpleName(), interfaceScope()), "Cannot assign a value of type integer to a variable of type string."); expectIssue( inferType("var stringVar : string = 0.5", VariableDefinition.class.getSimpleName(), interfaceScope()), "Cannot assign a value of type real to a variable of type string."); } // PrimitiveValueExpression @Test public void testValueOfSuccess() { assertTrue(isIntegerType(inferType("valueof(intEvent)"))); assertTrue(isBooleanType(inferType("valueof(boolEvent)"))); assertTrue(isRealType(inferType("valueof(realEvent)"))); assertTrue(isStringType(inferType("valueof(stringEvent)"))); assertTrue(isVoidType(inferType("valueof(voidEvent)"))); assertTrue(isIntegerType(inferType("valueof(ABC.intEvent)"))); } @Test public void testOperationSuccess() { assertTrue(isIntegerType(inferType("intVar = intOp()"))); } @Test public void testOperationFailure() { expectIssue(inferType("boolVar = intOp()"), "Assignment operator '=' may only be applied on compatible types, not on boolean and integer."); } @Test public void testParenthesizedExpression() { assertTrue(isBooleanType(inferType("( true || false )"))); assertTrue(isIntegerType(inferType("( 5 )"))); assertTrue(isRealType(inferType("( 7.5 / 1.2 )"))); assertTrue(isStringType(inferType("( 'abc' )"))); } @Test public void testTypeCastExpressionSuccess() { assertTrue(isBooleanType(inferType("( true as boolean)"))); assertTrue(isIntegerType(inferType("( 7.5 as integer )"))); assertTrue(isRealType(inferType(" 7 as real "))); assertTrue(isStringType(inferType("( 'abc' as string )"))); } @Test public void testTypeCastExpressionFailure() { expectIssue(inferType("true as integer"), "Cannot cast from boolean to integer."); expectIssue(inferType("true as string"), "Cannot cast from boolean to string."); expectIssue(inferType("5 as string"), "Cannot cast from integer to string."); expectIssue(inferType("5.5 as string"), "Cannot cast from real to string."); } @Test public void testTernaryExpression() { assertTrue(isIntegerType(inferType("(1<2) ? 4 : 5"))); assertTrue(isBooleanType(inferType("(true) ? false : true"))); expectIssue(inferType("(true) ? 4 : false"), "Could not determine a common type for integer and boolean."); } @Test public void testParameterizedType() { assertTrue(isBooleanType( inferTypeResultForExpression("t.prop1", "internal var t:ComplexParameterizedType<boolean, integer>").getType())); assertTrue(isIntegerType( inferTypeResultForExpression("t.prop2", "internal var t:ComplexParameterizedType<boolean, integer>").getType())); assertTrue(isBooleanType(inferTypeResultForExpression("t.prop1.prop1", "internal var t:ComplexParameterizedType<ComplexParameterizedType<boolean, integer>, integer>").getType())); expectNoErrors("b = t.op(true, 10)", "internal var t:ComplexParameterizedType<boolean, integer> var b:boolean"); assertTrue(isBooleanType(inferTypeResultForExpression("b = t.op(true, 10)", "internal var t:ComplexParameterizedType<integer> var b:boolean").getType())); assertTrue( isAnyType(inferTypeResultForExpression("t.prop1", "internal var t:ComplexParameterizedType<>").getType())); assertTrue(isAnyType(inferTypeResultForExpression("t.prop1", "internal var t:ComplexParameterizedType").getType())); assertTrue(isIntegerType(inferTypeResultForExpression("t.op(1, 2)", "internal var t:ComplexParameterizedType").getType())); expectNoErrors("b = t.op2()", "internal: var t:ComplexParameterizedType<integer, boolean> var b: boolean"); assertTrue(isAnyType(inferTypeResultForExpression("t.prop1.prop1", "internal var t:ComplexParameterizedType<ComplexParameterizedType<>, integer>").getType())); expectNoErrors("t2 = t.prop3", "internal " + "var t:ComplexParameterizedType<boolean, integer> " + "var t2:ComplexParameterizedType<integer, boolean>"); expectErrors("t = t.prop3", "internal " + "var t:ComplexParameterizedType<boolean, integer> " + "var t2:ComplexParameterizedType<integer, boolean>", ITypeSystemInferrer.NOT_SAME_CODE, 2); } @Test public void testOperationWithParameterizedType() { String scopes = "" + "internal " + "var t1:ComplexParameterizedType<boolean, integer>" + "var t2:ComplexParameterizedType<integer, boolean>" + "operation op(p:ComplexParameterizedType<boolean, integer>) : void"; expectNoErrors("op(t1)", scopes); expectErrors("op(t2)", scopes, ITypeSystemInferrer.NOT_SAME_CODE, 2); } @Test public void testNullType() { String scope = "internal var cp:ComplexType var i:integer"; expectNoErrors("cp == null", scope); expectNoErrors("null != cp", scope); expectNoErrors("cp = null", scope); expectIssue(inferTypeResult("null = cp", Expression.class.getSimpleName(), scope).getType(), "Assignment operator '=' may only be applied on compatible types, not on null and ComplexType."); expectIssue(inferTypeResult("i == null", Expression.class.getSimpleName(), scope).getType(), "Comparison operator '==' may only be applied on compatible types, not on integer and null."); expectIssue(inferTypeResult("i = null", Expression.class.getSimpleName(), scope).getType(), "Assignment operator '=' may only be applied on compatible types, not on integer and null."); } /** * Uses a model of the following function: * * template <typename T> * T genericOp(T a, T b) { * return a > b ? a : b; * } */ @Test public void testOperationWithTypeParameters() { String scopes = "" + "internal " + "var myI : integer " + "var myF : real " + "var myB: boolean " + "var myCPT: ComplexParameterizedType<boolean, integer> " + "var myCPT2: ComplexParameterizedType<integer, boolean> "; expectNoErrors("myI = genericOp(myI, myI)", scopes); assertTrue(isIntegerType(inferTypeResultForExpression("myI = genericOp(myI, myI)", scopes).getType())); expectNoErrors("myF = genericOp(3+5, 2.3)", scopes); assertTrue(isRealType(inferTypeResultForExpression("myF = genericOp(3+5, 2.3)", scopes).getType())); expectNoErrors("myCPT = genericOp(myCPT, myCPT)", scopes); expectError("myB = genericOp(myI, myI)", scopes, ITypeSystemInferrer.NOT_COMPATIBLE_CODE); expectError("myB = genericOp(3+5, boolean)", scopes, ITypeSystemInferrer.NOT_INFERRABLE_TYPE_PARAMETER_CODE); expectErrors("myCPT2 = genericOp(myCPT, myCPT)", scopes, ITypeSystemInferrer.NOT_SAME_CODE, 2); expectErrors("myCPT = genericOp(myCPT, myCPT2)", scopes, ITypeSystemInferrer.NOT_SAME_CODE, 2); } @Test public void testNestedGenericElementInferrer() { String scope = "" + "import nestedTemplate " + "internal: " + "var nestedCPT: ComplexParameterizedType<boolean, integer> " + "var myI: integer " + "var myB: boolean "; expectError("myI = nestedOp(3)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE); expectNoErrors("myI = nestedOp(nestedCPT)", scope); expectError("myB = nestedOp(nestedCPT)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE); } @Test public void testNestedNestedGenericElementInferrer() { String scope = "" + "import nestedNestedTemplate " + "internal: " + "var nestedCPT: ComplexParameterizedType<ComplexParameterizedType<boolean, string>, integer> " + "var myS: string " + "var b: boolean "; expectNoErrors("myS = nestedNestedOp(nestedCPT)", scope); expectError("b = nestedNestedOp(nestedCPT)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE); } @Test public void testGenericFeatureCall() { String scope = "" + "internal: " + "var cmo: ParameterizedMethodOwner " + "var i: integer " + "var r: real " + "var b: boolean "; expectNoErrors("i = cmo.genericOp(1, 2)", scope); expectNoErrors("r = cmo.genericOp(1.3, 2)", scope); expectNoErrors("r = cmo.genericOp(1, 2)", scope); expectNoErrors("b = cmo.genericOp(true, 2)", scope); expectNoErrors("b = cmo.genericOp(true, 2)", scope); expectError("i = cmo.genericOp(1.3, 2)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE); expectError("r = cmo.genericOp(false, 2)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE); expectError("b = cmo.genericOp(1.3, 2)", scope, ITypeSystemInferrer.NOT_COMPATIBLE_CODE); } }