Skip to content

Commit

Permalink
[javanaut]feat: Add Logical operation expr and unit test (#293)
Browse files Browse the repository at this point in the history
* Add LogicalOperationExpr and unit test
* Enable (&&) and (!!) operator
summer-ji-eng authored Sep 13, 2020

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 9ffbd10 commit 1fc408a
Showing 9 changed files with 278 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -55,6 +55,8 @@ public interface AstNodeVisitor {

public void visit(UnaryOperationExpr unaryOperationExpr);

public void visit(LogicalOperationExpr logicalOperationExpr);

/** =============================== COMMENT =============================== */
public void visit(LineComment lineComment);

Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// 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 LogicalOperationExpr 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 LogicalOperationExpr logicalAndWithExprs(Expr lhsExpr, Expr rhsExpr) {
return builder()
.setLhsExpr(lhsExpr)
.setRhsExpr(rhsExpr)
.setOperatorKind(OperatorKind.LOGICAL_AND)
.build();
}

// Convenience wrapper.
public static LogicalOperationExpr logicalOrWithExprs(Expr lhsExpr, Expr rhsExpr) {
return builder()
.setLhsExpr(lhsExpr)
.setRhsExpr(rhsExpr)
.setOperatorKind(OperatorKind.LOGICAL_OR)
.build();
}

private static Builder builder() {
return new AutoValue_LogicalOperationExpr.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 LogicalOperationExpr autoBuild();

private LogicalOperationExpr build() {
LogicalOperationExpr logicalOperationExpr = autoBuild();
TypeNode lhsExprType = logicalOperationExpr.lhsExpr().type();
TypeNode rhsExprType = logicalOperationExpr.rhsExpr().type();
OperatorKind operator = logicalOperationExpr.operatorKind();
final String errorMsg =
String.format(
"Logical operator %s is valid only on boolean or its boxed type, found %s, %s.",
operator, lhsExprType.toString(), rhsExprType.toString());
Preconditions.checkState(
lhsExprType.equals(TypeNode.BOOLEAN) && rhsExprType.equals(TypeNode.BOOLEAN), errorMsg);
return logicalOperationExpr;
}
}
}
Original file line number Diff line number Diff line change
@@ -18,6 +18,8 @@

public enum OperatorKind {
ARITHMETIC_ADDITION,
LOGICAL_AND,
LOGICAL_OR,
RELATIONAL_EQUAL_TO,
RELATIONAL_NOT_EQUAL_TO,
UNARY_LOGICAL_NOT,
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@
import com.google.api.generator.engine.ast.InstanceofExpr;
import com.google.api.generator.engine.ast.JavaDocComment;
import com.google.api.generator.engine.ast.LineComment;
import com.google.api.generator.engine.ast.LogicalOperationExpr;
import com.google.api.generator.engine.ast.MethodDefinition;
import com.google.api.generator.engine.ast.MethodInvocationExpr;
import com.google.api.generator.engine.ast.NewObjectExpr;
@@ -226,6 +227,12 @@ public void visit(UnaryOperationExpr unaryOperationExpr) {
unaryOperationExpr.expr().accept(this);
}

@Override
public void visit(LogicalOperationExpr logicalOperationExpr) {
logicalOperationExpr.lhsExpr().accept(this);
logicalOperationExpr.rhsExpr().accept(this);
}

/** =============================== STATEMENTS =============================== */
@Override
public void visit(ExprStatement exprStatement) {
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@
import com.google.api.generator.engine.ast.InstanceofExpr;
import com.google.api.generator.engine.ast.JavaDocComment;
import com.google.api.generator.engine.ast.LineComment;
import com.google.api.generator.engine.ast.LogicalOperationExpr;
import com.google.api.generator.engine.ast.MethodDefinition;
import com.google.api.generator.engine.ast.MethodInvocationExpr;
import com.google.api.generator.engine.ast.NewObjectExpr;
@@ -110,6 +111,8 @@ public class JavaWriterVisitor implements AstNodeVisitor {
private static final String OPERATOR_NOT_EQUAL_TO = "!=";
private static final String OPERATOR_INCREMENT = "++";
private static final String OPERATOR_LOGICAL_NOT = "!";
private static final String OPERATOR_LOGICAL_AND = "&&";
private static final String OPERATOR_LOGICAL_OR = "||";

private final StringBuffer buffer = new StringBuffer();
private final ImportWriterVisitor importWriterVisitor = new ImportWriterVisitor();
@@ -407,6 +410,15 @@ public void visit(UnaryOperationExpr unaryOperationExpr) {
}
}

@Override
public void visit(LogicalOperationExpr logicalOperationExpr) {
logicalOperationExpr.lhsExpr().accept(this);
space();
operator(logicalOperationExpr.operatorKind());
space();
logicalOperationExpr.rhsExpr().accept(this);
}

/** =============================== STATEMENTS =============================== */
@Override
public void visit(ExprStatement exprStatement) {
@@ -905,6 +917,12 @@ private void operator(OperatorKind kind) {
case ARITHMETIC_ADDITION:
buffer.append(OPERATOR_ADDITION);
break;
case LOGICAL_AND:
buffer.append(OPERATOR_LOGICAL_AND);
break;
case LOGICAL_OR:
buffer.append(OPERATOR_LOGICAL_OR);
break;
}
}
}
Original file line number Diff line number Diff line change
@@ -36,6 +36,7 @@ TESTS = [
"WhileStatementTest",
"ArithmeticOperationExprTest",
"UnaryOperationExprTest",
"LogicalOperationExprTest",
]

filegroup(
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// 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 LogicalOperationExprTest {
/** =============================== Logic And Operation Expr =============================== */
@Test
public void logicalAnd_validBasic() {
VariableExpr lhsExpr =
VariableExpr.withVariable(
Variable.builder().setType(TypeNode.BOOLEAN).setName("isGood").build());
VariableExpr rhsExpr =
VariableExpr.withVariable(
Variable.builder().setType(TypeNode.BOOLEAN).setName("isValid").build());
LogicalOperationExpr.logicalAndWithExprs(lhsExpr, rhsExpr);
// No exception thrown, so we succeeded.
}

@Test
public void logicalAnd_validBoxedBoolean() {
VariableExpr lhsExpr =
VariableExpr.withVariable(
Variable.builder().setType(TypeNode.BOOLEAN).setName("isGood").build());
VariableExpr rhsExpr =
VariableExpr.withVariable(
Variable.builder().setType(TypeNode.BOOLEAN_OBJECT).setName("isValid").build());
LogicalOperationExpr.logicalAndWithExprs(lhsExpr, rhsExpr);
// No exception thrown, so we succeeded.
}

@Test
public void logicalAnd_invalidNumericType() {
VariableExpr lhsExpr =
VariableExpr.withVariable(Variable.builder().setType(TypeNode.INT).setName("x").build());
VariableExpr rhsExpr =
VariableExpr.withVariable(
Variable.builder().setType(TypeNode.BOOLEAN).setName("isValid").build());
assertThrows(
IllegalStateException.class,
() -> LogicalOperationExpr.logicalAndWithExprs(lhsExpr, rhsExpr));
}

@Test
public void logicalAnd_invalidStringType() {
VariableExpr lhsExpr =
VariableExpr.withVariable(
Variable.builder().setType(TypeNode.BOOLEAN_OBJECT).setName("x").build());
VariableExpr rhsExpr =
VariableExpr.withVariable(
Variable.builder().setType(TypeNode.STRING).setName("isValid").build());
assertThrows(
IllegalStateException.class,
() -> LogicalOperationExpr.logicalAndWithExprs(lhsExpr, rhsExpr));
}

/** =============================== Logic Or Operation Expr =============================== */
@Test
public void logicalOr_validBoxedBoolean() {
VariableExpr lhsExpr =
VariableExpr.withVariable(
Variable.builder().setType(TypeNode.BOOLEAN_OBJECT).setName("isGood").build());
VariableExpr rhsExpr =
VariableExpr.withVariable(
Variable.builder().setType(TypeNode.BOOLEAN_OBJECT).setName("isValid").build());
LogicalOperationExpr.logicalOrWithExprs(lhsExpr, rhsExpr);
// No exception thrown, so we succeeded.
}

@Test
public void logicalOr_invalidVoidType() {
VariableExpr lhsExpr =
VariableExpr.withVariable(
Variable.builder().setType(TypeNode.BOOLEAN).setName("x").build());
MethodInvocationExpr rhsExpr =
MethodInvocationExpr.builder().setMethodName("doNothing").build();
assertThrows(
IllegalStateException.class,
() -> LogicalOperationExpr.logicalOrWithExprs(lhsExpr, rhsExpr));
}

@Test
public void logicalOr_invalidNullType() {
VariableExpr lhsExpr =
VariableExpr.withVariable(
Variable.builder().setType(TypeNode.BOOLEAN).setName("x").build());
ValueExpr rhsExpr = ValueExpr.withValue(NullObjectValue.create());
assertThrows(
IllegalStateException.class,
() -> LogicalOperationExpr.logicalOrWithExprs(lhsExpr, rhsExpr));
}
}
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@
import com.google.api.generator.engine.ast.ExprStatement;
import com.google.api.generator.engine.ast.IfStatement;
import com.google.api.generator.engine.ast.InstanceofExpr;
import com.google.api.generator.engine.ast.LogicalOperationExpr;
import com.google.api.generator.engine.ast.MethodDefinition;
import com.google.api.generator.engine.ast.MethodInvocationExpr;
import com.google.api.generator.engine.ast.NewObjectExpr;
@@ -938,6 +939,25 @@ public void writeUnaryOperationExprImports_PostIncrement() {
assertEquals(writerVisitor.write(), "import com.google.api.generator.engine.ast.Expr;\n\n");
}

@Test
public void writeLogicalOperationExprImports() {
MethodInvocationExpr lhsExpr =
MethodInvocationExpr.builder()
.setStaticReferenceType(
TypeNode.withReference(ConcreteReference.withClazz(UnaryOperationExpr.class)))
.setMethodName("isValid")
.setReturnType(TypeNode.BOOLEAN)
.build();
VariableExpr rhsExpr =
VariableExpr.builder().setVariable(createVariable("isGood", TypeNode.BOOLEAN)).build();
LogicalOperationExpr logicalOperationExpr =
LogicalOperationExpr.logicalAndWithExprs(lhsExpr, rhsExpr);
logicalOperationExpr.accept(writerVisitor);
assertEquals(
writerVisitor.write(),
"import com.google.api.generator.engine.ast.UnaryOperationExpr;\n\n");
}

private static TypeNode createType(Class clazz) {
return TypeNode.withReference(ConcreteReference.withClazz(clazz));
}
Original file line number Diff line number Diff line change
@@ -37,6 +37,7 @@
import com.google.api.generator.engine.ast.InstanceofExpr;
import com.google.api.generator.engine.ast.JavaDocComment;
import com.google.api.generator.engine.ast.LineComment;
import com.google.api.generator.engine.ast.LogicalOperationExpr;
import com.google.api.generator.engine.ast.MethodDefinition;
import com.google.api.generator.engine.ast.MethodInvocationExpr;
import com.google.api.generator.engine.ast.NewObjectExpr;
@@ -2057,6 +2058,38 @@ public void writeUnaryOperationExpr_logicalNot() {
assertThat(writerVisitor.write()).isEqualTo("!isEmpty()");
}

@Test
public void writeLogicalOperationExpr_logicalAnd() {
VariableExpr lhsExpr = VariableExpr.withVariable(createVariable("isEmpty", TypeNode.BOOLEAN));
VaporReference ref =
VaporReference.builder().setName("Student").setPakkage("com.google.example.v1").build();
TypeNode classType = TypeNode.withReference(ref);
MethodInvocationExpr rhsExpr =
MethodInvocationExpr.builder()
.setMethodName("isValid")
.setExprReferenceExpr(ValueExpr.withValue(ThisObjectValue.withType(classType)))
.setReturnType(TypeNode.BOOLEAN)
.build();
LogicalOperationExpr logicalOperationExpr =
LogicalOperationExpr.logicalAndWithExprs(lhsExpr, rhsExpr);
logicalOperationExpr.accept(writerVisitor);
assertThat(writerVisitor.write()).isEqualTo("isEmpty && this.isValid()");
}

@Test
public void writeLogicalOperationExpr_logicalOr() {
VariableExpr lhsExpr = VariableExpr.withVariable(createVariable("isGood", TypeNode.BOOLEAN));
MethodInvocationExpr rhsExpr =
MethodInvocationExpr.builder()
.setMethodName("isValid")
.setReturnType(TypeNode.BOOLEAN)
.build();
LogicalOperationExpr logicalOperationExpr =
LogicalOperationExpr.logicalOrWithExprs(lhsExpr, rhsExpr);
logicalOperationExpr.accept(writerVisitor);
assertThat(writerVisitor.write()).isEqualTo("isGood || isValid()");
}

private static String createLines(int numLines) {
return new String(new char[numLines]).replace("\0", "%s");
}

0 comments on commit 1fc408a

Please sign in to comment.