Skip to content

Commit

Permalink
support saving objects into xml files
Browse files Browse the repository at this point in the history
  • Loading branch information
sweetStreet committed Jun 21, 2023
1 parent 84d5612 commit 1fd193c
Show file tree
Hide file tree
Showing 29 changed files with 2,515 additions and 81 deletions.
22 changes: 6 additions & 16 deletions java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,6 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-util</artifactId>
<version>9.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-commons</artifactId>
<version>9.2</version>
</dependency>

<dependency>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
Expand All @@ -63,6 +47,12 @@
<artifactId>javaparser-symbol-solver-core</artifactId>
<version>3.23.1</version>
</dependency>

<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.20</version>
</dependency>
</dependencies>

<build>
Expand Down
19 changes: 19 additions & 0 deletions java/src/main/java/org/inlinetest/Constant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.inlinetest;

import java.util.Arrays;
import java.util.List;

import com.github.javaparser.ast.expr.AssignExpr;

public class Constant {
final static List<AssignExpr.Operator> COMPOUND_ASSIGN_OPERATORS = Arrays.asList(AssignExpr.Operator.PLUS,
AssignExpr.Operator.MINUS,
AssignExpr.Operator.MULTIPLY, AssignExpr.Operator.DIVIDE, AssignExpr.Operator.BINARY_AND,
AssignExpr.Operator.BINARY_OR, AssignExpr.Operator.XOR, AssignExpr.Operator.REMAINDER,
AssignExpr.Operator.LEFT_SHIFT, AssignExpr.Operator.SIGNED_RIGHT_SHIFT,
AssignExpr.Operator.UNSIGNED_RIGHT_SHIFT);
// enum type of statement: given statement, target statement, assertion statement
public enum StatementType {
GIVEN, TARGET, ASSERTION
}
}
21 changes: 21 additions & 0 deletions java/src/main/java/org/inlinetest/Here.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package org.inlinetest;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.security.AnyTypePermission;

public class Here {
public static XStream xstream = new XStream();

public Here() {
return;
}
Expand All @@ -9,6 +14,14 @@ public Here(String name) {
return;
}

public Here(int lineNo) {
return;
}

public Here(String name, int lineNo) {
return;
}

public Here checkEq(Object expected, Object actual) {
return this;
}
Expand All @@ -24,4 +37,12 @@ public Here checkTrue(Object value) {
public Here checkFalse(Object value) {
return this;
}

public static boolean group() {
return true;
}

static {
xstream.addPermission(AnyTypePermission.ANY);
}
}
204 changes: 195 additions & 9 deletions java/src/main/java/org/inlinetest/InlineTest.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
package org.inlinetest;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.inlinetest.Constant.StatementType;

import com.github.javaparser.JavaParser;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.AssignExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.expr.UnaryExpr;
import com.github.javaparser.ast.expr.VariableDeclarationExpr;
import com.github.javaparser.ast.stmt.AssertStmt;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.ExpressionStmt;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.ast.type.VoidType;

public class InlineTest {
public String testName;
public int lineNo;
public int targetStmtLineNo;
public List<Node> givens;
public List<Node> statement;
public Type targetType; // when target statement is assignment stmt, record the type of target in
// assignment stmt
public List<Node> assertions;
public List<Node> junitAssertions;

Expand All @@ -26,6 +44,10 @@ public InlineTest() {
}

public String toAssert() {
if (this.statement.size() == 0) {
return "";
}

StringBuilder sb = new StringBuilder();
// sb.append("@Test\n");
if (this.testName == null) {
Expand All @@ -48,47 +70,211 @@ public String toAssert() {
}

public MethodDeclaration toJunitMethod() {
if (this.statement.size() == 0) {
return null;
}

// create a method
if (testName == null) {
testName = "testLine" + String.valueOf(lineNo);
}

String testCaseName = "testLine" + String.valueOf(lineNo);

// add improts
BlockStmt block = new BlockStmt();

// visitor to rename variables
VariableRenameVisitor.Context context = new VariableRenameVisitor.Context();
VariableRenameVisitor vrVisitor = new VariableRenameVisitor();

// add givens
context.statementType = StatementType.GIVEN;

// sanity check if variable is initialized
Set<String> initializedVariables = new HashSet<String>();

for (int i = givens.size() - 1; i >= 0; i--) {
block.addStatement((Expression) givens.get(i));
}
for (Node n : statement) {
block.addStatement((Statement) n);
Expression expression = (Expression) givens.get(i).clone();
expression.accept(vrVisitor, context);
block.addStatement(expression);

if (givens.get(i) instanceof AssignExpr) {
Expression target = ((AssignExpr) givens.get(i)).getTarget();
if (target instanceof VariableDeclarationExpr) {
for (VariableDeclarator vd : ((VariableDeclarationExpr) target).getVariables()) {
String name = vd.getNameAsString();
if (initializedVariables.contains(name)) {
throw new RuntimeException("Variable " + name + " is initialized twice");
}
initializedVariables.add(vd.getNameAsString());
}
}
}
}
for (int i = assertions.size() - 1; i >= 0; i--) {
block.addStatement((Statement) assertions.get(i));

// rename variables in target statement if they are renamed in givens
if (statement.get(0) instanceof Statement) {
// target statement
context.statementType = StatementType.TARGET;
Statement targetStatement = (Statement) statement.get(0).clone();
// check assignment statement
if (targetStatement instanceof ExpressionStmt) {
Expression expressionInside = ((ExpressionStmt) targetStatement).getExpression();
if (expressionInside instanceof AssignExpr) {
Expression target = ((AssignExpr) expressionInside).getTarget();
Type targetType = this.targetType;

boolean variableInitialized = false;
for (Node given : givens) {
if (given instanceof AssignExpr) {
Expression givenTarget = ((AssignExpr) given).getTarget();
if (givenTarget instanceof VariableDeclarationExpr) {
for (VariableDeclarator vd : ((VariableDeclarationExpr) givenTarget).getVariables()) {
if (vd.getNameAsString().equals(target.toString())) {
variableInitialized = true;
}
}
}
}
}

if (!variableInitialized) {
if (targetType == null) {
throw new RuntimeException("Cannot resolve type of " + target.toString());
}
targetStatement.accept(vrVisitor, context);
if (!Constant.COMPOUND_ASSIGN_OPERATORS
.contains(((AssignExpr) expressionInside).getOperator())) {
targetStatement = StaticJavaParser
.parseStatement(targetType.toString() + " " + targetStatement.toString());
}
}
}
}
targetStatement.accept(vrVisitor, context);
block.addStatement(targetStatement);

// add assertions
context.statementType = StatementType.ASSERTION;

// sanity check if variable is asserted
Set<String> assertedVariables = new HashSet<String>();

for (int i = junitAssertions.size() - 1; i >= 0; i--) {
ExpressionStmt expressionStmt = new ExpressionStmt((Expression) junitAssertions.get(i)).clone();

Expression expression = expressionStmt.getExpression();
if (expression instanceof MethodCallExpr) {
MethodCallExpr methodCallExpr = (MethodCallExpr) expression;
if (methodCallExpr.getNameAsString().equals("assertEquals")) {
Expression firstArgument = methodCallExpr.getArgument(0);
if (firstArgument instanceof NameExpr) {
String name = ((NameExpr) firstArgument).getNameAsString();
if (assertedVariables.contains(name)) {
throw new RuntimeException("Variable " + name + " is asserted twice");
}
assertedVariables.add(name);
}
}
}

expressionStmt.accept(vrVisitor, context);
block.addStatement(expressionStmt);
}
} else if (statement.get(0) instanceof Expression) {
// target statement is if condition
Expression targetExpression = (Expression) statement.get(0);
for (int i = assertions.size() - 1; i >= 0; i--) {
// check if there is group()
// node is expected to be group() or !group()
Node node = assertions.get(i);
if (node instanceof AssertStmt) {
AssertStmt assertStmt = (AssertStmt) node;
Expression expression = assertStmt.getCheck();
if (expression instanceof MethodCallExpr) {
if (expression.toString().equals("group()")) {
// Statement builtAssertStmt = new AssertStmt(new
// EnclosedExpr(targetExpression)).clone();
Statement builtAssertStmt = new ExpressionStmt(
new MethodCallExpr().setName("assertTrue").addArgument(targetExpression)).clone();
builtAssertStmt.accept(vrVisitor, context);
block.addStatement(builtAssertStmt);
} else {
Statement builtAssertStmt = new ExpressionStmt(
new MethodCallExpr().setName("assertTrue").addArgument(expression)).clone();
builtAssertStmt.accept(vrVisitor, context);
block.addStatement(builtAssertStmt);
}
// else {
// throw new RuntimeException(
// "The expression is not a group() call: " + expression.toString());
// }
} else if (expression instanceof UnaryExpr) {
if (expression.toString().equals("!group()")) {
// assertFalse(targetExpression);
Statement builtAssertStmt = new ExpressionStmt(
new MethodCallExpr().setName("assertFalse").addArgument(targetExpression)).clone();
// UnaryExpr unaryExpr = (UnaryExpr) expression;
// Statement builtAssertStmt = new AssertStmt(
// new UnaryExpr(new EnclosedExpr(targetExpression),
// unaryExpr.getOperator())).clone();
builtAssertStmt.accept(vrVisitor, context);
block.addStatement(builtAssertStmt);
} else {
Statement builtAssertStmt = new ExpressionStmt(
new MethodCallExpr().setName("assertFalse").addArgument(((UnaryExpr)expression).getExpression())).clone();
builtAssertStmt.accept(vrVisitor, context);
block.addStatement(builtAssertStmt);
}
// else {
// throw new RuntimeException(
// "The expression is not a !group() call: " + expression.toString());
// }
} else {
Statement builtAssertStmt = new ExpressionStmt(
new MethodCallExpr().setName("assertTrue").addArgument(expression)).clone();
builtAssertStmt.accept(vrVisitor, context);
block.addStatement(builtAssertStmt);
}
} else {
throw new RuntimeException("The node is not an assert statement" + node.toString());
}
}
}
MethodDeclaration method = new MethodDeclaration();
method.setName(testName).setType(new VoidType()).setBody(block).addMarkerAnnotation("Test");

method.setName(testCaseName).setType(new VoidType()).setBody(block).addMarkerAnnotation("Test");
new JavaParser().parseClassOrInterfaceType("Exception").getResult().ifPresent(method::addThrownException);
return method;
}

public MethodDeclaration toAssertMethod() {
// create a method
if (this.statement.size() == 0) {
return null;
}

if (testName == null) {
testName = "testLine" + String.valueOf(lineNo);
}

// create a method
String testCaseName = "testLine" + String.valueOf(lineNo);

// TODO: add imports
BlockStmt block = new BlockStmt();
for (int i = givens.size() - 1; i >= 0; i--) {
block.addStatement((Expression) givens.get(i));
}
for (Node n : statement) {
// TODO: consider group()
block.addStatement((Statement) n);
}
for (int i = assertions.size() - 1; i >= 0; i--) {
block.addStatement((Statement) assertions.get(i));
}
MethodDeclaration method = new MethodDeclaration();
method.setName(testName).setType(new VoidType()).setBody(block);
method.setName(testCaseName).setType(new VoidType()).setBody(block);
return method;
}

Expand Down
Loading

0 comments on commit 1fd193c

Please sign in to comment.