/*---------------------------------------------------------------- * Copyright (c) ThoughtWorks, Inc. * Licensed under the Apache License, Version 2.0 * See LICENSE.txt in the project root for license information. *----------------------------------------------------------------*/ package com.thoughtworks.gauge.connection; import com.github.javaparser.JavaParser; import com.github.javaparser.ParseResult; import com.github.javaparser.Range; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import com.google.protobuf.ProtocolStringList; import com.thoughtworks.gauge.FileHelper; import com.thoughtworks.gauge.Logger; import gauge.messages.Messages; import gauge.messages.Spec; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; public class StubImplementationCodeProcessor implements com.thoughtworks.gauge.processor.IMessageProcessor { private static final String NEW_LINE = "\n"; private static ArrayList<MethodDeclaration> methodDeclarations = new ArrayList<>(); private static Range classRange; @Override public Messages.Message process(Messages.Message message) { ProtocolStringList stubs = message.getStubImplementationCodeRequest().getCodesList(); String filePath = message.getStubImplementationCodeRequest().getImplementationFilePath(); File file = new File(filePath); Messages.FileDiff fileDiff; if (file.exists()) { fileDiff = implementInExistingFile(stubs, file); } else { File fileName = FileHelper.getDefaultImplFileName("", 0); fileDiff = implementInNewClass(stubs, fileName); } return Messages.Message.newBuilder() .setMessageId(message.getMessageId()) .setFileDiff(fileDiff) .setMessageType(Messages.Message.MessageType.StubImplementationCodeRequest) .build(); } private Messages.FileDiff implementInExistingFile(ProtocolStringList stubs, File file) { try { if (new FileReader(file).read() != -1) { return implementInExistingClass(stubs, file); } return implementInNewClass(stubs, file); } catch (IOException e) { Logger.error("Unable to implement method", e); } return null; } private Messages.FileDiff implementInNewClass(ProtocolStringList stubs, File file) { String className = FileHelper.getClassName(file); String contents = getNewClassContents(className, stubs); Spec.Span.Builder span = Spec.Span.newBuilder() .setStart(0) .setStartChar(0) .setEnd(0) .setEndChar(0); Messages.TextDiff textDiff = Messages.TextDiff.newBuilder().setSpan(span).setContent(contents).build(); return Messages.FileDiff.newBuilder().setFilePath(file.toString()).addTextDiffs(textDiff).build(); } private String getNewClassContents(String className, ProtocolStringList stubs) { return "import com.thoughtworks.gauge.Step;" + NEW_LINE + NEW_LINE + "public class " + className + " {" + NEW_LINE + String.join(NEW_LINE, stubs) + NEW_LINE + "}" + NEW_LINE; } private Messages.FileDiff implementInExistingClass(ProtocolStringList stubs, File file) { try { JavaParser javaParser = new JavaParser(); ParseResult<CompilationUnit> compilationUnit = javaParser.parse(file); String contents = String.join(NEW_LINE, stubs); int lastLine; int column; MethodVisitor methodVisitor = new MethodVisitor(); methodVisitor.visit(compilationUnit.getResult().get(), null); if (!methodDeclarations.isEmpty()) { MethodDeclaration methodDeclaration = methodDeclarations.get(methodDeclarations.size() - 1); lastLine = methodDeclaration.getRange().get().end.line - 1; column = methodDeclaration.getRange().get().end.column + 1; contents = NEW_LINE + contents; } else { new ClassVisitor().visit(compilationUnit.getResult().get(), null); lastLine = classRange.end.line - 1; column = 0; contents = contents + NEW_LINE; } Spec.Span.Builder span = Spec.Span.newBuilder() .setStart(lastLine) .setStartChar(column) .setEnd(lastLine) .setEndChar(column); Messages.TextDiff textDiff = Messages.TextDiff.newBuilder().setSpan(span).setContent(contents).build(); return Messages.FileDiff.newBuilder().setFilePath(file.toString()).addTextDiffs(textDiff).build(); } catch (IOException e) { Logger.error("Unable to implement method", e); } return null; } private static class MethodVisitor extends VoidVisitorAdapter { @Override public void visit(MethodDeclaration methodDeclaration, Object arg) { methodDeclarations.add(methodDeclaration); } } private static class ClassVisitor extends VoidVisitorAdapter { @Override public void visit(ClassOrInterfaceDeclaration node, Object arg) { classRange = node.getRange().get(); } } }