diff --git a/BUILD.bazel b/BUILD.bazel index ca61266dfd..11b2b84ce0 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -15,6 +15,7 @@ JAVA_SRCS = [ TEST_SRCS = [ "//src/test/java/com/google/api/generator/engine:engine_files", "//src/test/java/com/google/api/generator/gapic:gapic_files", + "//src/test/java/com/google/api/generator/test/framework:framework_files", ] # ============= Proto wrappers ================= diff --git a/dependencies.properties b/dependencies.properties index feeea4cce5..42eb51736a 100644 --- a/dependencies.properties +++ b/dependencies.properties @@ -20,6 +20,7 @@ maven.com_google_code_findbugs_jsr305=com.google.code.findbugs:jsr305:3.0.0 maven.com_google_auto_value_auto_value=com.google.auto.value:auto-value:1.7.2 maven.com_google_auto_value_auto_value_annotations=com.google.auto.value:auto-value-annotations:1.7.2 maven.com_google_protobuf_protobuf_java=com.google.protobuf:protobuf-java:3.12.2 +maven.io_github_java_diff_utils=io.github.java-diff-utils:java-diff-utils:4.0 maven.javax_annotation_api=javax.annotation:javax.annotation-api:1.3.2 maven.javax_validation_javax_validation_api=javax.validation:validation-api:2.0.1.Final diff --git a/src/main/java/com/google/api/generator/engine/ast/AssignmentOperationExpr.java b/src/main/java/com/google/api/generator/engine/ast/AssignmentOperationExpr.java new file mode 100644 index 0000000000..6211b680a2 --- /dev/null +++ b/src/main/java/com/google/api/generator/engine/ast/AssignmentOperationExpr.java @@ -0,0 +1,145 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.api.generator.engine.ast; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Preconditions; + +@AutoValue +public abstract class AssignmentOperationExpr implements OperationExpr { + public abstract VariableExpr variableExpr(); + + public abstract Expr valueExpr(); + + public abstract OperatorKind operatorKind(); + + @Override + public TypeNode type() { + return variableExpr().type(); + } + + @Override + public void accept(AstNodeVisitor visitor) { + visitor.visit(this); + } + + public static AssignmentOperationExpr xorAssignmentWithExprs( + VariableExpr variableExpr, Expr valueExpr) { + return builder() + .setVariableExpr(variableExpr) + .setValueExpr(valueExpr) + .setOperatorKind(OperatorKind.ASSIGNMENT_XOR) + .build(); + } + + public static AssignmentOperationExpr multiplyAssignmentWithExprs( + VariableExpr variableExpr, Expr valueExpr) { + return builder() + .setVariableExpr(variableExpr) + .setValueExpr(valueExpr) + .setOperatorKind(OperatorKind.ASSIGNMENT_MULTIPLY) + .build(); + } + + private static Builder builder() { + return new AutoValue_AssignmentOperationExpr.Builder(); + } + + @AutoValue.Builder + abstract static class Builder { + // Private setter. + abstract Builder setVariableExpr(VariableExpr variableExpr); + + // Private setter. + abstract Builder setValueExpr(Expr valueExpr); + + // Private setter. + abstract Builder setOperatorKind(OperatorKind operator); + + abstract AssignmentOperationExpr autoBuild(); + + private AssignmentOperationExpr build() { + AssignmentOperationExpr assignmentOperationExpr = autoBuild(); + TypeNode lhsType = assignmentOperationExpr.variableExpr().variable().type(); + TypeNode rhsType = + assignmentOperationExpr.valueExpr() instanceof VariableExpr + ? ((VariableExpr) assignmentOperationExpr.valueExpr()).variable().type() + : assignmentOperationExpr.valueExpr().type(); + OperatorKind operator = assignmentOperationExpr.operatorKind(); + + // Check if the variable exprs have been declared, if yes, throw error. + Preconditions.checkState( + !assignmentOperationExpr.variableExpr().isDecl() + && (assignmentOperationExpr.valueExpr() instanceof VariableExpr + ? !((VariableExpr) assignmentOperationExpr.valueExpr()).isDecl() + : true), + String.format( + "Variable `%s` should not be declaration in the variable expression.", + assignmentOperationExpr.variableExpr().variable().name())); + + // TYPE_CHECK_ERROR_MSG is type checking error message for operators. + final String TYPE_CHECK_ERROR_MSG = + String.format( + "Assignment operator %s can not be applied to %s, %s.", + operator, lhsType.toString(), rhsType.toString()); + + // Check type for multiply and assignment operator (*=). + if (operator.equals(OperatorKind.ASSIGNMENT_MULTIPLY)) { + Preconditions.checkState( + isValidMultiplyAssignmentType(lhsType, rhsType), TYPE_CHECK_ERROR_MSG); + } + + // Check type for XOR and assignment operator (^=). + // TODO(summerji): Complete the type-checking for ^= and unit test. + if (operator.equals(OperatorKind.ASSIGNMENT_XOR)) { + Preconditions.checkState(isValidXORAssignmentType(lhsType, rhsType), TYPE_CHECK_ERROR_MSG); + } + return assignmentOperationExpr; + } + + // isValidMultiplyAssignmentType validates the types for LHS variable expr and RHS expr. + // *= can be only applied on Primitive numeric type. + private boolean isValidMultiplyAssignmentType(TypeNode variableType, TypeNode valueType) { + // LHS is numeric type, RHS should be any numeric type or any numeric boxed type. + if (TypeNode.isNumericType(variableType) && !TypeNode.isBoxedType(variableType)) { + return TypeNode.isNumericType(valueType); + } + // LHS is integer boxed type, RHS should be any numeric type except long, float, double. + if (variableType.equals(TypeNode.INT_OBJECT)) { + return TypeNode.isNumericType(valueType) + && !(valueType.equals(TypeNode.LONG) || TypeNode.isFloatingPointType(valueType)); + } + // LHS is long boxed type, RHS should be any numeric type except float, double. + if (variableType.equals(TypeNode.LONG_OBJECT)) { + return TypeNode.isNumericType(valueType) && !TypeNode.isFloatingPointType(valueType); + } + // LHS is integer boxed type, RHS should be any numeric type except double. + if (variableType.equals(TypeNode.FLOAT_OBJECT)) { + return TypeNode.isNumericType(valueType) && !valueType.equals(TypeNode.DOUBLE); + } + // LHS is integer boxed type, RHS should be any numeric type or any numeric boxed type. + if (variableType.equals(TypeNode.DOUBLE_OBJECT)) { + return TypeNode.isNumericType(valueType); + } + // *= operator does not support boxed Short, Character, Byte, null, reference, void type. + return false; + } + + // TODO(summerji): Complete the type-checking for ^= and unit test. + private boolean isValidXORAssignmentType(TypeNode variableType, TypeNode valueType) { + return true; + } + } +} diff --git a/src/main/java/com/google/api/generator/engine/ast/AstNodeVisitor.java b/src/main/java/com/google/api/generator/engine/ast/AstNodeVisitor.java index d2c7f0adad..32b0642619 100644 --- a/src/main/java/com/google/api/generator/engine/ast/AstNodeVisitor.java +++ b/src/main/java/com/google/api/generator/engine/ast/AstNodeVisitor.java @@ -55,8 +55,12 @@ public interface AstNodeVisitor { public void visit(UnaryOperationExpr unaryOperationExpr); + public void visit(RelationalOperationExpr relationalOperationExpr); + public void visit(LogicalOperationExpr logicalOperationExpr); + public void visit(AssignmentOperationExpr assignmentOperationExpr); + /** =============================== COMMENT =============================== */ public void visit(LineComment lineComment); diff --git a/src/main/java/com/google/api/generator/engine/ast/OperatorKind.java b/src/main/java/com/google/api/generator/engine/ast/OperatorKind.java index 5c5a6a4642..c5f9b1d158 100644 --- a/src/main/java/com/google/api/generator/engine/ast/OperatorKind.java +++ b/src/main/java/com/google/api/generator/engine/ast/OperatorKind.java @@ -20,6 +20,8 @@ public enum OperatorKind { ARITHMETIC_ADDITION, LOGICAL_AND, LOGICAL_OR, + ASSIGNMENT_XOR, + ASSIGNMENT_MULTIPLY, RELATIONAL_EQUAL_TO, RELATIONAL_NOT_EQUAL_TO, UNARY_LOGICAL_NOT, diff --git a/src/main/java/com/google/api/generator/engine/ast/RelationalOperationExpr.java b/src/main/java/com/google/api/generator/engine/ast/RelationalOperationExpr.java new file mode 100644 index 0000000000..cd8bf06766 --- /dev/null +++ b/src/main/java/com/google/api/generator/engine/ast/RelationalOperationExpr.java @@ -0,0 +1,138 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.api.generator.engine.ast; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Preconditions; + +@AutoValue +public abstract class RelationalOperationExpr implements OperationExpr { + public abstract Expr lhsExpr(); + + public abstract Expr rhsExpr(); + + public abstract OperatorKind operatorKind(); + + @Override + public TypeNode type() { + return TypeNode.BOOLEAN; + } + + @Override + public void accept(AstNodeVisitor visitor) { + visitor.visit(this); + } + + // Convenience wrapper. + public static RelationalOperationExpr equalToWithExprs(Expr lhsExpr, Expr rhsExpr) { + return builder() + .setLhsExpr(lhsExpr) + .setRhsExpr(rhsExpr) + .setOperatorKind(OperatorKind.RELATIONAL_EQUAL_TO) + .build(); + } + + // Convenience wrapper. + public static RelationalOperationExpr notEqualToWithExprs(Expr lhsExpr, Expr rhsExpr) { + return builder() + .setLhsExpr(lhsExpr) + .setRhsExpr(rhsExpr) + .setOperatorKind(OperatorKind.RELATIONAL_NOT_EQUAL_TO) + .build(); + } + + // TODO(summerji): Add convenience wrapper lessThanWithExprs + // public static RelationalOperationExpr lessThanWithExprs(Expr lhsExpr, Expr rhsExpr) { + // return builder() + // .setLhsExpr(lhsExpr) + // .setRhsExpr(rhsExpr) + // .setOperatorKind(OperatorKind.RELATIONAL_LESS_THAN) + // .build(); + // } + + private static Builder builder() { + return new AutoValue_RelationalOperationExpr.Builder(); + } + + @AutoValue.Builder + abstract static class Builder { + + // Private setter. + abstract Builder setLhsExpr(Expr expr); + + // Private setter. + abstract Builder setRhsExpr(Expr expr); + + // Private setter. + abstract Builder setOperatorKind(OperatorKind operator); + + abstract RelationalOperationExpr autoBuild(); + + private RelationalOperationExpr build() { + RelationalOperationExpr relationalOperationExpr = autoBuild(); + TypeNode lhsExprType = relationalOperationExpr.lhsExpr().type(); + TypeNode rhsExprType = relationalOperationExpr.rhsExpr().type(); + OperatorKind operator = relationalOperationExpr.operatorKind(); + final String errorMsg = + String.format( + "Relational operator %s can not be applied to %s, %s.", + operator, lhsExprType.toString(), rhsExprType.toString()); + + if (operator.equals(OperatorKind.RELATIONAL_EQUAL_TO) + || operator.equals(OperatorKind.RELATIONAL_NOT_EQUAL_TO)) { + Preconditions.checkState(isValidEqualityType(lhsExprType, rhsExprType), errorMsg); + } + + return relationalOperationExpr; + } + + // isValidEqualityType checks expressions' type for equality operator (==) and non-equality + // operator (!=). + private boolean isValidEqualityType(TypeNode lhsType, TypeNode rhsType) { + // If the expression's types are matched, return true + if (lhsType.equals(rhsType)) { + return true; + } + + // If the expressions' type are array, the types should be array and matched, or either is + // null type; + if (lhsType.isArray() || rhsType.isArray()) { + return lhsType.equals(TypeNode.NULL) || rhsType.equals(TypeNode.NULL); + } + + // If lhs expression type is numeric type (char, byte, short, int, long, double), the rhs + // expression type should be any numeric type or any numeric boxed type + if (TypeNode.isNumericType(lhsType) && TypeNode.isNumericType(rhsType)) { + return true; + } + + // If lhs expression type is new Object or null, the rhs type should be a reference type or + // null or boxed type; + if (lhsType.equals(TypeNode.OBJECT) || lhsType.equals(TypeNode.NULL)) { + return TypeNode.isReferenceType(rhsType) + || rhsType.equals(TypeNode.OBJECT) + || rhsType.equals(TypeNode.NULL); + } + + // If lhs expression type is Boxed type or a referenced type, rhs should be null or object, + // other cases have been covered in previous conditions. + if (TypeNode.isBoxedType(lhsType) || TypeNode.isReferenceType(lhsType)) { + return rhsType.equals(TypeNode.NULL) || rhsType.equals(TypeNode.OBJECT); + } + + return false; + } + } +} diff --git a/src/main/java/com/google/api/generator/engine/ast/TypeNode.java b/src/main/java/com/google/api/generator/engine/ast/TypeNode.java index adc16f1f26..d7d368d650 100644 --- a/src/main/java/com/google/api/generator/engine/ast/TypeNode.java +++ b/src/main/java/com/google/api/generator/engine/ast/TypeNode.java @@ -145,7 +145,16 @@ public static boolean isNumericType(TypeNode type) { || type.equals(TypeNode.DOUBLE) || type.equals(TypeNode.SHORT) || type.equals(TypeNode.FLOAT) - || type.equals(TypeNode.CHAR); + || type.equals(TypeNode.CHAR) + || type.equals(TypeNode.BYTE); + } + + public static boolean isFloatingPointType(TypeNode type) { + return type.equals(TypeNode.DOUBLE) || type.equals(TypeNode.FLOAT); + } + + public static boolean isBoxedType(TypeNode type) { + return isReferenceType(type) && BOXED_TYPE_MAP.containsValue(type); } public boolean isPrimitiveType() { diff --git a/src/main/java/com/google/api/generator/engine/writer/ImportWriterVisitor.java b/src/main/java/com/google/api/generator/engine/writer/ImportWriterVisitor.java index fadfaaad0d..94af63747e 100644 --- a/src/main/java/com/google/api/generator/engine/writer/ImportWriterVisitor.java +++ b/src/main/java/com/google/api/generator/engine/writer/ImportWriterVisitor.java @@ -18,6 +18,7 @@ import com.google.api.generator.engine.ast.AnonymousClassExpr; import com.google.api.generator.engine.ast.ArithmeticOperationExpr; import com.google.api.generator.engine.ast.AssignmentExpr; +import com.google.api.generator.engine.ast.AssignmentOperationExpr; import com.google.api.generator.engine.ast.AstNodeVisitor; import com.google.api.generator.engine.ast.BlockComment; import com.google.api.generator.engine.ast.BlockStatement; @@ -40,6 +41,7 @@ import com.google.api.generator.engine.ast.NewObjectExpr; import com.google.api.generator.engine.ast.Reference; import com.google.api.generator.engine.ast.ReferenceConstructorExpr; +import com.google.api.generator.engine.ast.RelationalOperationExpr; import com.google.api.generator.engine.ast.ReturnExpr; import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.Statement; @@ -227,12 +229,24 @@ public void visit(UnaryOperationExpr unaryOperationExpr) { unaryOperationExpr.expr().accept(this); } + @Override + public void visit(RelationalOperationExpr relationalOperationExpr) { + relationalOperationExpr.lhsExpr().accept(this); + relationalOperationExpr.rhsExpr().accept(this); + } + @Override public void visit(LogicalOperationExpr logicalOperationExpr) { logicalOperationExpr.lhsExpr().accept(this); logicalOperationExpr.rhsExpr().accept(this); } + @Override + public void visit(AssignmentOperationExpr assignmentOperationExpr) { + assignmentOperationExpr.variableExpr().accept(this); + assignmentOperationExpr.valueExpr().accept(this); + } + /** =============================== STATEMENTS =============================== */ @Override public void visit(ExprStatement exprStatement) { diff --git a/src/main/java/com/google/api/generator/engine/writer/JavaWriterVisitor.java b/src/main/java/com/google/api/generator/engine/writer/JavaWriterVisitor.java index ff99718c74..90ed3c21ec 100644 --- a/src/main/java/com/google/api/generator/engine/writer/JavaWriterVisitor.java +++ b/src/main/java/com/google/api/generator/engine/writer/JavaWriterVisitor.java @@ -18,6 +18,7 @@ import com.google.api.generator.engine.ast.AnonymousClassExpr; import com.google.api.generator.engine.ast.ArithmeticOperationExpr; import com.google.api.generator.engine.ast.AssignmentExpr; +import com.google.api.generator.engine.ast.AssignmentOperationExpr; import com.google.api.generator.engine.ast.AstNodeVisitor; import com.google.api.generator.engine.ast.BlockComment; import com.google.api.generator.engine.ast.BlockStatement; @@ -40,6 +41,7 @@ import com.google.api.generator.engine.ast.NewObjectExpr; import com.google.api.generator.engine.ast.OperatorKind; import com.google.api.generator.engine.ast.ReferenceConstructorExpr; +import com.google.api.generator.engine.ast.RelationalOperationExpr; import com.google.api.generator.engine.ast.ReturnExpr; import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.Statement; @@ -113,6 +115,8 @@ public class JavaWriterVisitor implements AstNodeVisitor { private static final String OPERATOR_LOGICAL_NOT = "!"; private static final String OPERATOR_LOGICAL_AND = "&&"; private static final String OPERATOR_LOGICAL_OR = "||"; + private static final String OPERATOR_XOR = "^="; + private static final String OPERATOR_MULTIPLE_AND_ASSIGNMENT = "*="; private final StringBuffer buffer = new StringBuffer(); private final ImportWriterVisitor importWriterVisitor = new ImportWriterVisitor(); @@ -410,6 +414,15 @@ public void visit(UnaryOperationExpr unaryOperationExpr) { } } + @Override + public void visit(RelationalOperationExpr relationalOperationExpr) { + relationalOperationExpr.lhsExpr().accept(this); + space(); + operator(relationalOperationExpr.operatorKind()); + space(); + relationalOperationExpr.rhsExpr().accept(this); + } + @Override public void visit(LogicalOperationExpr logicalOperationExpr) { logicalOperationExpr.lhsExpr().accept(this); @@ -419,6 +432,15 @@ public void visit(LogicalOperationExpr logicalOperationExpr) { logicalOperationExpr.rhsExpr().accept(this); } + @Override + public void visit(AssignmentOperationExpr assignmentOperationExpr) { + assignmentOperationExpr.variableExpr().accept(this); + space(); + operator(assignmentOperationExpr.operatorKind()); + space(); + assignmentOperationExpr.valueExpr().accept(this); + } + /** =============================== STATEMENTS =============================== */ @Override public void visit(ExprStatement exprStatement) { @@ -902,6 +924,15 @@ private void semicolon() { private void operator(OperatorKind kind) { switch (kind) { + case ARITHMETIC_ADDITION: + buffer.append(OPERATOR_ADDITION); + break; + case ASSIGNMENT_XOR: + buffer.append(OPERATOR_XOR); + break; + case ASSIGNMENT_MULTIPLY: + buffer.append(OPERATOR_MULTIPLE_AND_ASSIGNMENT); + break; case RELATIONAL_EQUAL_TO: buffer.append(OPERATOR_EQUAL_TO); break; @@ -914,9 +945,6 @@ private void operator(OperatorKind kind) { case UNARY_LOGICAL_NOT: buffer.append(OPERATOR_LOGICAL_NOT); break; - case ARITHMETIC_ADDITION: - buffer.append(OPERATOR_ADDITION); - break; case LOGICAL_AND: buffer.append(OPERATOR_LOGICAL_AND); break; diff --git a/src/test/java/com/google/api/generator/engine/ast/AssignmentOperationExprTest.java b/src/test/java/com/google/api/generator/engine/ast/AssignmentOperationExprTest.java new file mode 100644 index 0000000000..5c0a48568f --- /dev/null +++ b/src/test/java/com/google/api/generator/engine/ast/AssignmentOperationExprTest.java @@ -0,0 +1,662 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.api.generator.engine.ast; + +import static org.junit.Assert.assertThrows; + +import org.junit.Test; + +public class AssignmentOperationExprTest { + /** =========== Multiply And Assignment Operators: Variable is declaration ================ */ + @Test + public void multiplyAndAssignmentOperationExpr_invalidVariableExprIsDecl() { + Variable variable = Variable.builder().setName("x").setType(TypeNode.INT).build(); + VariableExpr lhsExpr = VariableExpr.builder().setVariable(variable).setIsDecl(true).build(); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidValueExprIsDecl() { + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + Variable variable = Variable.builder().setName("x").setType(TypeNode.INT).build(); + VariableExpr rhsExpr = VariableExpr.builder().setVariable(variable).setIsDecl(true).build(); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidVariableExprAndValueExprIsDecl() { + Variable lVariable = Variable.builder().setName("x").setType(TypeNode.INT).build(); + VariableExpr lhsExpr = VariableExpr.builder().setVariable(lVariable).setIsDecl(true).build(); + Variable rVariable = Variable.builder().setName("y").setType(TypeNode.INT).build(); + VariableExpr rhsExpr = VariableExpr.builder().setVariable(rVariable).setIsDecl(true).build(); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + /** ========= Multiply And Assignment Operators: VariableExpr is numeric types ============== */ + @Test + public void multiplyAndAssignmentOperationExpr_validNumericMatched() { + // No need swap test case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validNumericUnmatched() { + // No need swap test case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + ValueExpr rhsExpr = createValueExpr(TypeNode.INT, "5"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validNumericMatchedBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validIntegerMatchedBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validNumericUnmatchedBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validIntegerBoxedWithShortType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validNumericWithFloatType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithFloatType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validDoubleWithIntegerBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithDoubleType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.DOUBLE, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validDoubleWithLongBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidLongBoxedWithDoubleType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.DOUBLE, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validLongWithIntegerBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithLongType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.LONG, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validIntegerWithFloatBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validFloatBoxedWithIntegerType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validFloatWithLongBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidLongBoxedWithFloatType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidNumericWithBooleanBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidBooleanBoxedWithNumericType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidNumericWithBooleanType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidNumericWithBooleanType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidNumericWithReferenceType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidReferencedWithNumericType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.STRING, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidNumericWithNewObject() { + // No Need swap case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + NewObjectExpr rhsExpr = NewObjectExpr.withType(TypeNode.OBJECT); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + /** ==== Multiply And Assignment Operators: LHS data type is boolean and its boxed type ===== */ + @Test + public void multiplyAndAssignmentOperationExpr_invalidBooleanWithNumericType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidNumericWithBooleanType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidBooleanBoxedWithNumericType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidNumericWithBooleanBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "x"); + ValueExpr rhsExpr = createValueExpr(TypeNode.INT, "5"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + /** ======== Multiply And Assignment Operators: LHS data type is Integer Box Type ============ */ + // RHS should be int, char, short, byte or these types' boxed types. + @Test + public void multiplyAndAssignmentOperationExpr_validIntegerMatchedBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validNumericMatchedBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + ValueExpr rhsExpr = createValueExpr(TypeNode.INT, "5"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validIntegerBoxedWithShortType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validNumericUnmatchedBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.SHORT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validIntegerBoxedWithShortBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validShortBoxedWithIntegerBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.SHORT_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validIntegerBoxedWithCharacterBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validShortBoxedWithIntegerBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.CHAR_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validIntegerBoxedWithByteBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validByteBoxedWithIntegerBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BYTE_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithFloatType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validNumericWithFloatType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithFloatBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validFloatBoxedWithIntegerBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithDoubleType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validDoubleWithIntegerBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithDoubleBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validDoubleBoxedWithIntegerBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithLongType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validLongWithIntegerBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.LONG, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithLongBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validLongBoxedWithIntegerBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + /** ==== Multiply And Assignment Operators: LHS data type is Float boxed type ====== */ + // RHS could be numeric or numeric boxed type, beside double and its boxed type. + @Test + public void multiplyAndAssignmentOperationExpr_validFloatBoxedWithIntegerType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validIntegerWithFloatBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + ValueExpr rhsExpr = createValueExpr(TypeNode.INT, "5"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validFloatBoxedWithIntegerBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithFloatBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validFloatBoxedWithCharBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidCharBoxedWithFloatBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.CHAR_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validFloatBoxedWithByteBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidByteBoxedWithFloatBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BYTE_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validFloatBoxedWithLongBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidLongBoxedWithFloatBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidFloatBoxedWithDoubleBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validDoubleBoxedWithFloatBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidFloatBoxedWithObjectType() { + // No need swap case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + NewObjectExpr rhsExpr = NewObjectExpr.withType(TypeNode.OBJECT); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidFloatBoxedWithNullType() { + // No need swap case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create()); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidFloatBoxedWithReferenceType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidReferenceWithFloatBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.STRING, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + /** ==== Multiply And Assignment Operators: LHS data type is Short/Char/Byte Boxed Type ====== */ + // RHS has no valid type. + @Test + public void multiplyAndAssignmentOperationExpr_invalidByteBoxedWithIntegerBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validIntegerBoxedWithByteBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BYTE_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidShortBoxedWithIntegerBoxedType() { + // Swap test case in + // "multiplyAndAssignmentOperationExpr_validCharacterBoxedWithIntegerBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.SHORT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_validCharacterBoxedWithIntegerBoxedType() { + // Swap test case in + // "multiplyAndAssignmentOperationExpr_validIntegerBoxedWithCharacterBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.CHAR_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidCharBoxedWithFloatBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithFloatBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.CHAR_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidByteBoxedWithFloatBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validFloatBoxedWithByteBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BYTE_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + /** ======== Multiply And Assignment Operators: LHS data type is Double Boxed Type ============ */ + // RHS could be any numeric type or numeric boxed type. + @Test + public void multiplyAndAssignmentOperationExpr_validDoubleBoxedWithIntegerBoxedType() { + // Swap test case in + // "multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithDoubleBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validDoubleBoxedWithFloatBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidFloatBoxedWithDoubleBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_validDoubleBoxedWithLongBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidLongBoxedWithDoubleBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidDoubleBoxedWithReferenceType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidReferenceWithDoubleBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "x"); + ValueExpr valueExpr = ValueExpr.withValue(StringObjectValue.withValue("abc")); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, valueExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidDoubleBoxedWithNullType() { + // No need swap case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "x"); + ValueExpr valueExprExpr = ValueExpr.withValue(NullObjectValue.create()); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, valueExprExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidDoubleBoxedWithOjectType() { + // No need swap test. + VariableExpr lhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "x"); + NewObjectExpr rhsExpr = NewObjectExpr.withType(TypeNode.OBJECT); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + /** ======== Multiply And Assignment Operators: LHS data type is Long boxed type ============ */ + @Test + public void multiplyAndAssignmentOperationExpr_validLongBoxedWithIntegerBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidIntegerBoxedWithLongBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidLongBoxedWithFloatBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validFloatBoxedWithLongBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidLongBoxedWithFloatType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validFloatWithLongBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidLongBoxedWithDoubleBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validDoubleBoxedWithLongBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidLongBoxedWithDoubleType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_validDoubleWithLongBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidLongBoxedWithNullType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidNullWithLongBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "x"); + ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create()); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidLongBoxedWithObjectType() { + // No need swap case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "x"); + NewObjectExpr rhsExpr = NewObjectExpr.withType(TypeNode.OBJECT); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidLongBoxedWithReferenceType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidReferenceWithLongBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.STRING, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + /** ======== Multiply And Assignment Operators: LHS data type is Reference Type ============ */ + @Test + public void multiplyAndAssignmentOperationExpr_invalidReferencedWithNumericType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidNumericWithReferenceType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidReferenceWithFloatBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidFloatBoxedWithReferenceType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidReferenceWithLongBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidLongBoxedWithReferenceType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.LONG_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void multiplyAndAssignmentOperationExpr_invalidReferenceWithDoubleBoxedType() { + // Swap test case in "multiplyAndAssignmentOperationExpr_invalidDoubleBoxedWithReferenceType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr)); + } + + /** ======================= Multiply And Assignment Operators: Void type ===================== */ + @Test + public void multiplyAndAssignmentOperationExpr_invalidWithOneVoidType() { + // No need swap case. + VariableExpr lhsExprExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + MethodInvocationExpr rhsExpr = + MethodInvocationExpr.builder().setMethodName("x").setReturnType(TypeNode.VOID).build(); + assertThrows( + IllegalStateException.class, + () -> AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExprExpr, rhsExpr)); + } + + // TODO(summerji): Complete the type-checking for ^= and unit test. + /** ================== Bitwise Exclusive Or And Assignment Operators: ======================== */ + // createVariableExpr is help function to create a variable expr. + private VariableExpr createVariableExpr(TypeNode type, String name) { + Variable variable = Variable.builder().setName(name).setType(type).build(); + VariableExpr lhsExpr = VariableExpr.withVariable(variable); + return lhsExpr; + } + + // createValueExpr is help function to create a value expr. + private ValueExpr createValueExpr(TypeNode type, String value) { + PrimitiveValue primitiveValue = PrimitiveValue.builder().setType(type).setValue(value).build(); + ValueExpr valueExpr = ValueExpr.withValue(primitiveValue); + return valueExpr; + } +} diff --git a/src/test/java/com/google/api/generator/engine/ast/BUILD.bazel b/src/test/java/com/google/api/generator/engine/ast/BUILD.bazel index 9809e2fa11..dda0ab0ac3 100644 --- a/src/test/java/com/google/api/generator/engine/ast/BUILD.bazel +++ b/src/test/java/com/google/api/generator/engine/ast/BUILD.bazel @@ -36,7 +36,9 @@ TESTS = [ "WhileStatementTest", "ArithmeticOperationExprTest", "UnaryOperationExprTest", + "RelationalOperationExprTest", "LogicalOperationExprTest", + "AssignmentOperationExprTest", ] filegroup( diff --git a/src/test/java/com/google/api/generator/engine/ast/RelationalOperationExprTest.java b/src/test/java/com/google/api/generator/engine/ast/RelationalOperationExprTest.java new file mode 100644 index 0000000000..251aadf44a --- /dev/null +++ b/src/test/java/com/google/api/generator/engine/ast/RelationalOperationExprTest.java @@ -0,0 +1,779 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.api.generator.engine.ast; + +import static org.junit.Assert.assertThrows; + +import com.google.api.generator.engine.ast.TypeNode.TypeKind; +import org.junit.Test; + +public class RelationalOperationExprTest { + /** ==================== Equality Operators: LHS data type is numeric ======================= */ + @Test + public void equalToOperationExpr_validBasic() { + // LHS: numeric type, RHS: matched numeric type. + // No need swap LHS and RHS test case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validNumericTYpe() { + // LHS: numeric type, RHS: unmatched numeric type. + // No need swap LHS and RHS test case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.CHAR, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.LONG, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void notEqualToOperationExpr_validMatchedNumericBoxTYpe() { + // LHS: numeric type, RHS: matched numeric Boxed type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validBoxedWithMatchedUnBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "y"); + RelationalOperationExpr.notEqualToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void notEqualToOperationExpr_validNumericBoxTYpe() { + // LHS: numeric type, RHS: unmatched numeric Boxed type. + // Swapping LHS and RHS test case is covered in + // equalToOperationExpr_validBoxedWithUnmatchedUnBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "y"); + RelationalOperationExpr.notEqualToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_invalidNumericBooleanBoxedType() { + // LHS: numeric type, RHS: boolean boxed Type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidBoxedBooleanWithNumericType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void notEqualToOperationExpr_invalidNumericStringType() { + // LHS: numeric type, RHS: referenced type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidReferenceWithNumericType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.DOUBLE, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.STRING, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.notEqualToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void notEqualToOperationExpr_invalidNumericNullType() { + // LHS: numeric type, RHS: null. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidNullWithNumericType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.DOUBLE, "x"); + ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create()); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.notEqualToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidNumericBooleanType() { + // LHS: numeric type, RHS: boolean boxed Type. + // Swapping LHS and RHS test case is covered in + // notEqualToOperationExpr_invalidBooleanToNumericType. + VariableExpr lhsExpr = createVariableExpr(TypeNode.LONG, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidNumericTypeWithArrayType() { + // LHS: Numeric Type, RHS: Array with numeric type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidArrayWithNotArrayType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT, "x"); + VariableExpr rhsExpr = + createVariableExpr( + TypeNode.builder().setIsArray(true).setTypeKind(TypeKind.INT).build(), "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + /** =============== Equality Operators: LHS data type is numeric boxed type ================ */ + @Test + public void equalToOperationExpr_validBoxedWithMatchedBoxedType() { + // LHS: Boxed type, RHS: Matched Boxed. + // No need swap LHS and RHS test case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + RelationalOperationExpr.equalToWithExprs(rhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validBoxedWithMatchedUnBoxedType() { + // LHS: Boxed type, RHS: Unmatched Boxed. + // Swapping LHS and RHS test case is covered in + // "notEqualToOperationExpr_validMatchedNumericBoxTYpe". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.FLOAT, "y"); + RelationalOperationExpr.equalToWithExprs(rhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validBoxedWithUnmatchedUnBoxedType() { + // LHS: Numeric boxed type, RHS: other numeric type. + // Swapping LHS and RHS test case is covered in "notEqualToOperationExpr_validNumericBoxTYpe". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validNumericBoxedWithNullType() { + // LHS: Boxed type, RHS: Null. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validNullWithNumericBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create()); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validNumericBoxedWithNewObjectType() { + // LHS: Numeric boxed type, RHS: new object. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validObjectWithNumericBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + NewObjectExpr rhsExpr = NewObjectExpr.withType(TypeNode.OBJECT); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_invalidNumericBoxedWithBooleanType() { + // LHS: Numeric boxed type, RHS: Boolean type. + // Swapping LHS and RHS test case is covered in + // "notEqualToOperationExpr_invalidBooleanToOtherBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidNumericBoxedWithBooleanBoxedType() { + // LHS: Numeric boxed type, RHS: Boolean Boxed type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidBooleanBoxedWithNumericBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidNumericBoxedWithReferenceType() { + // LHS: Numeric boxed type, RHS: Reference type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidReferenceWithNumericBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.FLOAT_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.STRING, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + /** ============= Equality Operators: LHS data type is boolean or its boxed type ============== */ + @Test + public void equalToOperationExpr_validBooleanType() { + // LHS: boolean type, RHS: boolean Type. + // No need swap LHS and RHS test case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validRHSBooleanBoxedType() { + // LHS: boolean type, RHS: boolean boxed Type. + // Swapping LHS and RHS test case is covered in "equalToOperationExpr_validLHSBooleanBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validLHSBooleanBoxedType() { + // LHS: boolean boxed type, RHS: boolean Type. + // Swapping LHS and RHS test case is covered in "equalToOperationExpr_validRHSBooleanBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void notEqualToOperationExpr_validBooleanBoxedToNullType() { + // LHS: boolean boxed type, RHS: null. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validNullWithBooleanBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "x"); + ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create()); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void notEqualToOperationExpr_validBooleanBoxedToObjectType() { + // LHS: boolean boxed type, RHS: null. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validObjectWithBooleanBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.OBJECT, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void notEqualToOperationExpr_invalidBooleanToNumericType() { + // LHS: boolean type, RHS: char boxed type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidNumericBooleanType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.CHAR, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.notEqualToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void notEqualToOperationExpr_invalidBooleanToOtherBoxedType() { + // LHS: boolean type, RHS: numeric boxed type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidNumericBoxedWithBooleanType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.CHAR_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.notEqualToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void notEqualToOperationExpr_invalidBooleanToReferenceType() { + // LHS: boolean type, RHS: object type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidReferenceWithBooleanType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.STRING, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.notEqualToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidBooleanWithNullType() { + // LHS: boolean type, RHS: null type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidNullWithBooleanType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN, "x"); + ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create()); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidBooleanWithObjectType() { + // LHS: boolean type, RHS: object type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidObjectWithBooleanType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidBoxedBooleanWithNumericType() { + // LHS: boolean boxed type, RHS: numeric + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidNumericBooleanBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidBooleanBoxedWithNumericBoxedType() { + // LHS: boolean boxed type, RHS: numeric + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidNumericBoxedWithBooleanBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidBoxedBooleanWithReferencedType() { + // LHS: boolean boxed type, RHS: reference type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidReferenceWithBooleanBoxedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.STRING, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + /** ===================== Equality Operators: LHS data type is Array ======================== */ + @Test + public void equalToOperationExpr_validArrayWithMatchedType() { + // LHS: Array with numeric type, RHS: Array with matched numeric type. + // No need swap LHS and RHS test case. + VariableExpr lhsExpr = + createVariableExpr( + TypeNode.builder().setIsArray(true).setTypeKind(TypeKind.INT).build(), "x"); + VariableExpr rhsExpr = + createVariableExpr( + TypeNode.builder().setIsArray(true).setTypeKind(TypeKind.INT).build(), "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validArrayWithNullType() { + // LHS: Array with numeric type, RHS: null + // Swapping LHS and RHS test case is covered in "equalToOperationExpr_validANullWithArrayType". + VariableExpr lhsExpr = + createVariableExpr( + TypeNode.builder().setIsArray(true).setTypeKind(TypeKind.INT).build(), "x"); + NullObjectValue nullObjectValue = NullObjectValue.create(); + ValueExpr rhsExpr = ValueExpr.withValue(nullObjectValue); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void notEqualToOperationExpr_invalidArrayWithUnmatchedType() { + // LHS: Array with numeric type, RHS: Array with unmatched numeric type. + // No need swap LHS and RHS test case. + VariableExpr lhsExpr = + createVariableExpr( + TypeNode.builder().setIsArray(true).setTypeKind(TypeKind.INT).build(), "x"); + VariableExpr rhsExpr = + createVariableExpr( + TypeNode.builder().setIsArray(true).setTypeKind(TypeKind.CHAR).build(), "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.notEqualToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidArrayWithNotArrayType() { + // LHS: Array with numeric type, RHS: not Array + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidNumericTypeWithArrayType". + VariableExpr lhsExpr = + createVariableExpr( + TypeNode.builder().setIsArray(true).setTypeKind(TypeKind.INT).build(), "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidArrayWithObjectType() { + // LHS: Array with numeric type, RHS: New Object type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidObjectTypeWithArray". + VariableExpr lhsExpr = + createVariableExpr( + TypeNode.builder().setIsArray(true).setTypeKind(TypeKind.INT).build(), "x"); + NewObjectExpr rhsExpr = NewObjectExpr.withType(TypeNode.OBJECT); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + /** ================== Equality Operators: LHS data type is reference type =================== */ + @Test + public void equalToOperationExpr_validReferenceWithMatchedType() { + // LHS: String type, RHS: matched String type. + // No need swap LHS and RHS test case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.STRING, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validReferenceWithNullType() { + // LHS: String type, RHS: null. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validNullWithReferenceType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create()); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validReferenceWithObjectType() { + // LHS: String type, RHS: New object type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validObjectWithStringType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + NewObjectExpr rhsExpr = NewObjectExpr.withType(TypeNode.OBJECT); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validAnyObjectTypeWithObject() { + // LHS: Any reference type, RHS: Object type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validObjectWithAnyObjectType". + TypeNode someType = + TypeNode.withReference( + VaporReference.builder() + .setName("SomeClass") + .setPakkage("com.google.api.some.pakkage") + .build()); + VariableExpr lhsExpr = createVariableExpr(someType, "y"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.OBJECT, "x"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validAnyReferenceTypeWithNull() { + // LHS: Any reference type, RHS: Null type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validNullWithAnyReferenceType". + TypeNode someType = + TypeNode.withReference( + VaporReference.builder() + .setName("SomeClass") + .setPakkage("com.google.api.some.pakkage") + .build()); + VariableExpr lhsExpr = createVariableExpr(someType, "y"); + ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create()); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_invalidReferenceWithUnmatchedReferenceType() { + // LHS: String type, RHS: Unmatched reference type. + // No need swap LHS and RHS test case. + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + TypeNode someType = + TypeNode.withReference( + VaporReference.builder() + .setName("SomeClass") + .setPakkage("com.google.api.some.pakkage") + .build()); + VariableExpr rhsExpr = createVariableExpr(someType, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidReferenceWithNumericType() { + // LHS: String type, RHS: Numeric type + // Swapping LHS and RHS test case is covered in + // "notEqualToOperationExpr_invalidNumericStringType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidReferenceWithNumericBoxedType() { + // LHS: String type, RHS: numeric boxed type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidNumericBoxedWithReferenceType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidReferenceWithBooleanType() { + // LHS: String type, RHS: Boolean boxed type. + // Swapping LHS and RHS test case is covered in + // "notEqualToOperationExpr_invalidBooleanToReferenceType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidReferenceWithBooleanBoxedType() { + // LHS: String type, RHS: Boolean boxed type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidBoxedBooleanWithReferencedType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.STRING, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + /** ================== Equality Operators: LHS data type is Object or null =================== */ + @Test + public void equalToOperationExpr_validObjectWithAnyObjectType() { + // LHS: Object type, RHS: Any reference type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validAnyObjectTypeWithObject". + VariableExpr lhsExpr = createVariableExpr(TypeNode.OBJECT, "x"); + TypeNode someType = + TypeNode.withReference( + VaporReference.builder() + .setName("SomeClass") + .setPakkage("com.google.api.some.pakkage") + .build()); + VariableExpr rhsExpr = createVariableExpr(someType, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validNullWithAnyReferenceType() { + // LHS: Null type, RHS: any reference type + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validAnyReferenceTypeWithNull". + ValueExpr lhsExpr = ValueExpr.withValue(NullObjectValue.create()); + TypeNode someType = + TypeNode.withReference( + VaporReference.builder() + .setName("SomeClass") + .setPakkage("com.google.api.some.pakkage") + .build()); + VariableExpr rhsExpr = createVariableExpr(someType, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validObjectWithNullType() { + // LHS: Object, RHS: Null. + // Swapping LHS and RHS test case is covered in "equalToOperationExpr_validNullWithObjectType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.OBJECT, "x"); + ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create()); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validNullWithObjectType() { + // LHS: Null, RHS: Object. + // Swapping LHS and RHS test case is covered in "equalToOperationExpr_validObjectWithNullType". + VariableExpr rhsExpr = createVariableExpr(TypeNode.OBJECT, "x"); + ValueExpr lhsExpr = ValueExpr.withValue(NullObjectValue.create()); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validNullWithNullType() { + // LHS: Null, RHS: Null. + // No need swap LHS and RHS test case. + ValueExpr lhsExpr = ValueExpr.withValue(NullObjectValue.create()); + ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create()); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validObjectWithStringType() { + // LHS: Object type, RHS: Reference type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validReferenceWithObjectType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.STRING, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validObjectWithBooleanBoxedType() { + // LHS: Object type, RHS: Boolean boxed type. + // Swapping LHS and RHS test case is covered in + // "notEqualToOperationExpr_validBooleanBoxedToObjectType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validObjectWithNumericBoxedType() { + // LHS: Object type, RHS: Any Boxed type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validNumericBoxedWithNewObjectType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.SHORT_OBJECT, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validNullWithReferenceType() { + // LHS: Null type, RHS: Reference type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validNullWithReferenceType". + ValueExpr lhsExpr = ValueExpr.withValue(NullObjectValue.create()); + VariableExpr rhsExpr = createVariableExpr(TypeNode.STRING, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validNullWithBooleanBoxedType() { + // LHS: Object type, RHS: Any Boxed type + // Swapping LHS and RHS test case is covered in + // "notEqualToOperationExpr_validBooleanBoxedToNullType". + ValueExpr lhsExpr = ValueExpr.withValue(NullObjectValue.create()); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN_OBJECT, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validNullWithNumericBoxedType() { + // LHS: Object type, RHS: Any Boxed type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_validNumericBoxedWithNullType". + ValueExpr lhsExpr = ValueExpr.withValue(NullObjectValue.create()); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE_OBJECT, "y"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_validANullWithArrayType() { + // LHS: Null, RHS: Array with numeric type. + // Swapping LHS and RHS test case is covered in "equalToOperationExpr_validArrayWithNullType". + NullObjectValue nullObjectValue = NullObjectValue.create(); + ValueExpr lhsExpr = ValueExpr.withValue(nullObjectValue); + VariableExpr rhsExpr = + createVariableExpr( + TypeNode.builder().setIsArray(true).setTypeKind(TypeKind.INT).build(), "x"); + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + // No exception thrown, so we succeeded. + } + + @Test + public void equalToOperationExpr_invalidNullWithNumericType() { + // LHS: Null type, RHS: Nny Numeric type. + // Swapping LHS and RHS test case is covered in + // "notEqualToOperationExpr_invalidNumericNullType". + ValueExpr lhsExpr = ValueExpr.withValue(NullObjectValue.create()); + VariableExpr rhsExpr = createVariableExpr(TypeNode.INT, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidNullWithBooleanType() { + // LHS: Null type, RHS: Boolean type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidBooleanWithNullType". + ValueExpr lhsExpr = ValueExpr.withValue(NullObjectValue.create()); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidObjectWithNumericType() { + // LHS: Object type, RHS: Any Numeric type. + VariableExpr lhsExpr = createVariableExpr(TypeNode.OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.DOUBLE, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidObjectWithBooleanType() { + // LHS: Object type, RHS: Boolean type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidBooleanWithObjectType". + VariableExpr lhsExpr = createVariableExpr(TypeNode.OBJECT, "x"); + VariableExpr rhsExpr = createVariableExpr(TypeNode.BOOLEAN, "y"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + @Test + public void equalToOperationExpr_invalidObjectTypeWithArray() { + // LHS: New Object type, RHS: Array with numeric type. + // Swapping LHS and RHS test case is covered in + // "equalToOperationExpr_invalidArrayWithObjectType". + NewObjectExpr lhsExpr = NewObjectExpr.withType(TypeNode.OBJECT); + VariableExpr rhsExpr = + createVariableExpr( + TypeNode.builder().setIsArray(true).setTypeKind(TypeKind.INT).build(), "x"); + assertThrows( + IllegalStateException.class, + () -> RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr)); + } + + private VariableExpr createVariableExpr(TypeNode type, String name) { + Variable variable = Variable.builder().setName(name).setType(type).build(); + VariableExpr variableExpr = VariableExpr.withVariable(variable); + return variableExpr; + } +} diff --git a/src/test/java/com/google/api/generator/engine/ast/TypeNodeTest.java b/src/test/java/com/google/api/generator/engine/ast/TypeNodeTest.java index 5e559db5a7..8462a0cb71 100644 --- a/src/test/java/com/google/api/generator/engine/ast/TypeNodeTest.java +++ b/src/test/java/com/google/api/generator/engine/ast/TypeNodeTest.java @@ -117,4 +117,26 @@ public void invalidType_topLevelWildcard() { assertThrows( IllegalStateException.class, () -> TypeNode.withReference(ConcreteReference.wildcard())); } + + @Test + public void isBoxedType_basic() { + assertTrue(TypeNode.isBoxedType(TypeNode.INT_OBJECT)); + assertTrue(TypeNode.isBoxedType(TypeNode.BOOLEAN_OBJECT)); + assertTrue(TypeNode.isBoxedType(TypeNode.DOUBLE_OBJECT)); + assertTrue( + TypeNode.isBoxedType(TypeNode.withReference(ConcreteReference.withClazz(Long.class)))); + + assertFalse(TypeNode.isBoxedType(TypeNode.BOOLEAN)); + assertFalse(TypeNode.isBoxedType(TypeNode.INT)); + assertFalse(TypeNode.isBoxedType(TypeNode.FLOAT)); + + assertFalse(TypeNode.isBoxedType(TypeNode.STRING)); + TypeNode someType = + TypeNode.withReference( + VaporReference.builder() + .setName("SomeClass") + .setPakkage("com.google.api.generator.engine") + .build()); + assertFalse(TypeNode.isBoxedType(someType)); + } } diff --git a/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java b/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java index d82683a843..352b52379e 100644 --- a/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java +++ b/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java @@ -37,6 +37,7 @@ import com.google.api.generator.engine.ast.NullObjectValue; import com.google.api.generator.engine.ast.Reference; import com.google.api.generator.engine.ast.ReferenceConstructorExpr; +import com.google.api.generator.engine.ast.RelationalOperationExpr; import com.google.api.generator.engine.ast.ReturnExpr; import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.SuperObjectValue; @@ -939,6 +940,37 @@ public void writeUnaryOperationExprImports_PostIncrement() { assertEquals(writerVisitor.write(), "import com.google.api.generator.engine.ast.Expr;\n\n"); } + @Test + public void writeRelationalOperationExprImports() { + MethodInvocationExpr lhsExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(TypeNode.withReference(ConcreteReference.withClazz(Expr.class))) + .setMethodName("getSomething") + .setReturnType(TypeNode.STRING) + .build(); + TypeNode someType = + TypeNode.withReference( + VaporReference.builder() + .setName("SomeClass") + .setPakkage("com.google.api.generator.engine") + .build()); + MethodInvocationExpr rhsExpr = + MethodInvocationExpr.builder() + .setMethodName("getName") + .setStaticReferenceType(someType) + .setReturnType(TypeNode.STRING) + .build(); + RelationalOperationExpr relationalOperationExpr = + RelationalOperationExpr.equalToWithExprs(lhsExpr, rhsExpr); + relationalOperationExpr.accept(writerVisitor); + assertEquals( + writerVisitor.write(), + String.format( + createLines(2), + "import com.google.api.generator.engine.SomeClass;\n", + "import com.google.api.generator.engine.ast.Expr;\n\n")); + } + @Test public void writeLogicalOperationExprImports() { MethodInvocationExpr lhsExpr = diff --git a/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java b/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java index afe36c3430..e796e39e37 100644 --- a/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java +++ b/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java @@ -21,6 +21,7 @@ import com.google.api.generator.engine.ast.AnonymousClassExpr; import com.google.api.generator.engine.ast.ArithmeticOperationExpr; import com.google.api.generator.engine.ast.AssignmentExpr; +import com.google.api.generator.engine.ast.AssignmentOperationExpr; import com.google.api.generator.engine.ast.BlockComment; import com.google.api.generator.engine.ast.BlockStatement; import com.google.api.generator.engine.ast.CastExpr; @@ -45,6 +46,7 @@ import com.google.api.generator.engine.ast.PrimitiveValue; import com.google.api.generator.engine.ast.Reference; import com.google.api.generator.engine.ast.ReferenceConstructorExpr; +import com.google.api.generator.engine.ast.RelationalOperationExpr; import com.google.api.generator.engine.ast.ReturnExpr; import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.Statement; @@ -2058,6 +2060,45 @@ public void writeUnaryOperationExpr_logicalNot() { assertThat(writerVisitor.write()).isEqualTo("!isEmpty()"); } + @Test + public void writeRelationalOperationExpr_equalTo() { + VariableExpr variableExprLHS = + VariableExpr.withVariable( + Variable.builder().setType(TypeNode.BOOLEAN_OBJECT).setName("isGood").build()); + MethodInvocationExpr methodInvocationExpr = + MethodInvocationExpr.builder() + .setMethodName("isBad") + .setReturnType(TypeNode.BOOLEAN) + .build(); + + RelationalOperationExpr equalToOperationExpr = + RelationalOperationExpr.equalToWithExprs(variableExprLHS, methodInvocationExpr); + equalToOperationExpr.accept(writerVisitor); + assertThat(writerVisitor.write()).isEqualTo("isGood == isBad()"); + } + + @Test + public void writeRelationOperationExpr_notEqualTo() { + TypeNode someType = + TypeNode.withReference( + VaporReference.builder() + .setName("SomeClass") + .setPakkage("com.google.api.generator.engine") + .build()); + MethodInvocationExpr lhsExpr = + MethodInvocationExpr.builder() + .setMethodName("getName") + .setStaticReferenceType(someType) + .setReturnType(TypeNode.STRING) + .build(); + ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create()); + + RelationalOperationExpr notEqualToOperationExpr = + RelationalOperationExpr.notEqualToWithExprs(lhsExpr, rhsExpr); + notEqualToOperationExpr.accept(writerVisitor); + assertThat(writerVisitor.write()).isEqualTo("SomeClass.getName() != null"); + } + @Test public void writeLogicalOperationExpr_logicalAnd() { VariableExpr lhsExpr = VariableExpr.withVariable(createVariable("isEmpty", TypeNode.BOOLEAN)); @@ -2090,6 +2131,39 @@ public void writeLogicalOperationExpr_logicalOr() { assertThat(writerVisitor.write()).isEqualTo("isGood || isValid()"); } + @Test + public void writeAssignmentOperationExpr_multiplyAssignment() { + VariableExpr lhsExpr = createVariableExpr("h", TypeNode.INT); + ValueExpr rhsExpr = + ValueExpr.withValue( + PrimitiveValue.builder().setType(TypeNode.INT).setValue("1000003").build()); + AssignmentOperationExpr assignmentOperationExpr = + AssignmentOperationExpr.multiplyAssignmentWithExprs(lhsExpr, rhsExpr); + assignmentOperationExpr.accept(writerVisitor); + assertThat(writerVisitor.write()).isEqualTo("h *= 1000003"); + } + + @Test + public void writeAssignmentOperationExpr_xorAssignment() { + VariableExpr lhsExpr = createVariableExpr("h", TypeNode.INT); + TypeNode objectType = + TypeNode.withReference( + VaporReference.builder().setName("Objects").setPakkage("java.lang.Object").build()); + MethodInvocationExpr rhsExpr = + MethodInvocationExpr.builder() + .setReturnType(TypeNode.INT) + .setMethodName("hashCode") + .setStaticReferenceType(objectType) + .setArguments( + Arrays.asList( + VariableExpr.withVariable(createVariable("fixedValue", TypeNode.OBJECT)))) + .build(); + AssignmentOperationExpr assignmentOperationExpr = + AssignmentOperationExpr.xorAssignmentWithExprs(lhsExpr, rhsExpr); + assignmentOperationExpr.accept(writerVisitor); + assertThat(writerVisitor.write()).isEqualTo("h ^= Objects.hashCode(fixedValue)"); + } + private static String createLines(int numLines) { return new String(new char[numLines]).replace("\0", "%s"); } diff --git a/src/test/java/com/google/api/generator/gapic/dummy/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/dummy/BUILD.bazel index 84e4febc7a..ace0cd26f4 100644 --- a/src/test/java/com/google/api/generator/gapic/dummy/BUILD.bazel +++ b/src/test/java/com/google/api/generator/gapic/dummy/BUILD.bazel @@ -12,10 +12,12 @@ filegroup( [java_test( name = test_name, srcs = ["{0}.java".format(test_name)], + data = ["//src/test/java/com/google/api/generator/gapic/dummy/goldens:goldens_files"], test_class = "com.google.api.generator.gapic.dummy.{0}".format(test_name), deps = [ "//src/main/java/com/google/api/generator/engine/ast", "//src/main/java/com/google/api/generator/engine/writer", + "//src/test/java/com/google/api/generator/test/framework", "@junit_junit//jar", ], ) for test_name in TESTS] diff --git a/src/test/java/com/google/api/generator/gapic/dummy/FileDiffInfraDummyTest.java b/src/test/java/com/google/api/generator/gapic/dummy/FileDiffInfraDummyTest.java index 9dcc0ce252..98f766cab5 100644 --- a/src/test/java/com/google/api/generator/gapic/dummy/FileDiffInfraDummyTest.java +++ b/src/test/java/com/google/api/generator/gapic/dummy/FileDiffInfraDummyTest.java @@ -14,14 +14,15 @@ package com.google.api.generator.gapic.dummy; -import static junit.framework.Assert.assertEquals; - import com.google.api.generator.engine.ast.BlockComment; import com.google.api.generator.engine.ast.ClassDefinition; import com.google.api.generator.engine.ast.CommentStatement; import com.google.api.generator.engine.ast.LineComment; import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.writer.JavaWriterVisitor; +import com.google.api.generator.test.framework.Assert; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; import org.junit.Test; @@ -33,6 +34,9 @@ public class FileDiffInfraDummyTest { // created. // // TODO(xiaozhenliu): remove this test class once the file-diff infra is in place and well-tested. + private static final String GOLDENFILES_DIRECTORY = + "src/test/java/com/google/api/generator/gapic/dummy/goldens/"; + @Test public void simpleClass() { ClassDefinition classDef = @@ -47,7 +51,9 @@ public void simpleClass() { .build(); JavaWriterVisitor visitor = new JavaWriterVisitor(); classDef.accept(visitor); - assertEquals(visitor.write(), EXPECTED_CLASS_STRING_SIMPLE); + Path goldenFilePath = + Paths.get(GOLDENFILES_DIRECTORY, "FileDiffInfraDummyTestSimpleClass.golden"); + Assert.assertCodeEquals(goldenFilePath, visitor.write()); } @Test @@ -63,7 +69,18 @@ public void classWithHeader() { .build(); JavaWriterVisitor visitor = new JavaWriterVisitor(); classDef.accept(visitor); - assertEquals(visitor.write(), EXPECTED_CLASS_STRING_WITH_HEADER); + Path goldenFilePath = + Paths.get(GOLDENFILES_DIRECTORY, "FileDiffInfraDummyTestClassWithHeader.golden"); + Assert.assertCodeEquals(goldenFilePath, visitor.write()); + } + + // Add a simple test for two strings comparison. + @Test + public void simpleLineComment() { + JavaWriterVisitor visitor = new JavaWriterVisitor(); + LineComment lineComment = LineComment.withComment("test strings comparison."); + lineComment.accept(visitor); + Assert.assertCodeEquals("// test strings comparison.", visitor.write()); } private static final String APACHE_LICENSE_STRING = @@ -77,28 +94,4 @@ public void classWithHeader() { + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" + "See the License for the specific language governing permissions and\n" + "limitations under the License."; - - private static final String EXPECTED_CLASS_STRING_SIMPLE = - "package com.google.showcase.v1beta1.stub;\n\n" - + "// This is a test class for file-diff infra\n" - + "public class EchoStubSettings {}\n"; - - private static final String EXPECTED_CLASS_STRING_WITH_HEADER = - "/*\n" - + " * Copyright 2020 Google LLC\n" - + " *\n" - + " * Licensed under the Apache License, Version 2.0 (the \"License\");\n" - + " * you may not use this file except in compliance with the License.\n" - + " * You may obtain a copy of the License at\n" - + " *\n" - + " * https://www.apache.org/licenses/LICENSE-2.0\n" - + " *\n" - + " * Unless required by applicable law or agreed to in writing, software\n" - + " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" - + " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" - + " * See the License for the specific language governing permissions and\n" - + " * limitations under the License.\n" - + " */\n\n" - + "package com.google.showcase.v1beta1.stub;\n\n" - + "public class EchoStubSettings {}\n"; } diff --git a/src/test/java/com/google/api/generator/test/framework/Assert.java b/src/test/java/com/google/api/generator/test/framework/Assert.java new file mode 100644 index 0000000000..4ed6a932fd --- /dev/null +++ b/src/test/java/com/google/api/generator/test/framework/Assert.java @@ -0,0 +1,44 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.api.generator.test.framework; + +import java.nio.file.Path; +import java.util.List; +import junit.framework.AssertionFailedError; + +public class Assert { + /** + * Assert that the generated code is identical with the content in corresponding golden file. The + * differences will be emitted to the test-logs if any. + * + * @param goldenPath the path of the golden file. + * @param codegen the generated source code. + */ + public static void assertCodeEquals(Path goldenPath, String codegen) { + List diffList = Differ.diff(goldenPath, codegen); + if (!diffList.isEmpty()) { + throw new AssertionFailedError("Differences found: \n" + String.join("\n", diffList)); + } + } + + // Assert that two strings are identical, else throw AssertionFailedError and emit the + // differences to the test-logs. + public static void assertCodeEquals(String expected, String codegen) { + List diffList = Differ.diff(expected, codegen); + if (!diffList.isEmpty()) { + throw new AssertionFailedError("Differences found: \n" + String.join("\n", diffList)); + } + } +} diff --git a/src/test/java/com/google/api/generator/test/framework/BUILD.bazel b/src/test/java/com/google/api/generator/test/framework/BUILD.bazel new file mode 100644 index 0000000000..8cdc676778 --- /dev/null +++ b/src/test/java/com/google/api/generator/test/framework/BUILD.bazel @@ -0,0 +1,17 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "framework_files", + srcs = glob(["*.java"]), +) + +java_library( + name = "framework", + srcs = [ + ":framework_files", + ], + deps = [ + "@io_github_java_diff_utils//jar", + "@junit_junit//jar", + ], +) diff --git a/src/test/java/com/google/api/generator/test/framework/Differ.java b/src/test/java/com/google/api/generator/test/framework/Differ.java new file mode 100644 index 0000000000..6a3c364d33 --- /dev/null +++ b/src/test/java/com/google/api/generator/test/framework/Differ.java @@ -0,0 +1,71 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.api.generator.test.framework; + +import com.github.difflib.DiffUtils; +import com.github.difflib.UnifiedDiffUtils; +import com.github.difflib.algorithm.DiffException; +import com.github.difflib.patch.Patch; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; + +public class Differ { + private static final String LINE_SPLITTER = "\\r?\\n"; + + public static List diff(Path goldenFilePath, String codegen) { + List revised = Arrays.asList(codegen.split(LINE_SPLITTER)); + List original = null; + try { + original = Files.readAllLines(goldenFilePath); + } catch (IOException e) { + throw new GoldenFileReadException( + String.format("Error occurs when reading golden file %s", goldenFilePath)); + } + return diffTwoStringLists(original, revised); + } + + public static List diff(String expectedStr, String actualStr) { + List revised = Arrays.asList(actualStr.split(LINE_SPLITTER)); + List original = Arrays.asList(expectedStr.split(LINE_SPLITTER)); + return diffTwoStringLists(original, revised); + } + + private static List diffTwoStringLists(List original, List revised) { + Patch diff = null; + try { + diff = DiffUtils.diff(original, revised); + } catch (DiffException e) { + throw new ComputeDiffException("Could not compute the differences."); + } + List unifiedDiff = + UnifiedDiffUtils.generateUnifiedDiff("golden", "codegen", original, diff, 2); + return unifiedDiff; + } + + private static class GoldenFileReadException extends RuntimeException { + public GoldenFileReadException(String errorMessage) { + super(errorMessage); + } + } + + private static class ComputeDiffException extends RuntimeException { + public ComputeDiffException(String errorMessage) { + super(errorMessage); + } + } +}