diff --git a/client/src/features/annotatedPackageData/model/InferableAnnotation.ts b/client/src/features/annotatedPackageData/model/InferableAnnotation.ts index 543cdb04a..f4748d84e 100644 --- a/client/src/features/annotatedPackageData/model/InferableAnnotation.ts +++ b/client/src/features/annotatedPackageData/model/InferableAnnotation.ts @@ -14,7 +14,7 @@ import { RenameAnnotation, } from '../../annotations/annotationSlice'; -const dataPathPrefix = 'com.larsreimann.api_editor.server.data.'; +const dataPathPrefix = 'com.larsreimann.api_editor.model.'; const getDefaultValueTypeSuffix = (type: DefaultType) => { switch (type) { diff --git a/gradle.properties b/gradle.properties index cb6fbf555..ea80d44ee 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,7 @@ javaVersion=17 -ktorVersion=1.6.4 -logbackVersion=1.2.6 +ktorVersion=1.6.6 +logbackVersion=1.2.7 +xtextVersion=2.26.0.M2 org.gradle.caching=true kotlin.code.style=official diff --git a/server/build.gradle.kts b/server/build.gradle.kts index 1234132e9..12f2e081a 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -1,7 +1,7 @@ val javaVersion: String by project val ktorVersion: String by project val logbackVersion: String by project - +val xtextVersion: String by project // Plugins ------------------------------------------------------------------------------------------------------------- @@ -22,7 +22,6 @@ java { } } - // Dependencies -------------------------------------------------------------------------------------------------------- dependencies { @@ -32,6 +31,10 @@ dependencies { implementation("io.ktor:ktor-server-host-common:$ktorVersion") implementation("io.ktor:ktor-server-netty:$ktorVersion") + // We can later pull this from Maven Central (or some other repo) once published + implementation(files("lib/de.unibonn.simpleml-1.0.0-SNAPSHOT.jar")) + implementation("org.eclipse.xtext:org.eclipse.xtext:$xtextVersion") + testImplementation(kotlin("test")) testImplementation("io.kotest:kotest-assertions-core-jvm:5.0.2") testImplementation("io.ktor:ktor-server-test-host:$ktorVersion") diff --git a/server/lib/de.unibonn.simpleml-1.0.0-SNAPSHOT.jar b/server/lib/de.unibonn.simpleml-1.0.0-SNAPSHOT.jar new file mode 100644 index 000000000..9d996c580 Binary files /dev/null and b/server/lib/de.unibonn.simpleml-1.0.0-SNAPSHOT.jar differ diff --git a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/ClassAdapterContentBuilder.java b/server/src/main/java/com/larsreimann/api_editor/codegen/ClassAdapterContentBuilder.java similarity index 77% rename from server/src/main/java/com/larsreimann/api_editor/server/file_handling/ClassAdapterContentBuilder.java rename to server/src/main/java/com/larsreimann/api_editor/codegen/ClassAdapterContentBuilder.java index dbe9ad66e..ae9b7f751 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/ClassAdapterContentBuilder.java +++ b/server/src/main/java/com/larsreimann/api_editor/codegen/ClassAdapterContentBuilder.java @@ -1,12 +1,12 @@ -package com.larsreimann.api_editor.server.file_handling; +package com.larsreimann.api_editor.codegen; -import com.larsreimann.api_editor.server.data.AnnotatedPythonClass; -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction; +import com.larsreimann.api_editor.io.FileBuilder; +import com.larsreimann.api_editor.model.AnnotatedPythonClass; import java.util.ArrayList; import java.util.List; -class ClassAdapterContentBuilder extends FileBuilder { +public class ClassAdapterContentBuilder extends FileBuilder { AnnotatedPythonClass pythonClass; /** @@ -14,7 +14,7 @@ class ClassAdapterContentBuilder extends FileBuilder { * * @param pythonClass The module whose adapter content should be built */ - protected ClassAdapterContentBuilder(AnnotatedPythonClass pythonClass) { + public ClassAdapterContentBuilder(AnnotatedPythonClass pythonClass) { this.pythonClass = pythonClass; } @@ -23,7 +23,7 @@ protected ClassAdapterContentBuilder(AnnotatedPythonClass pythonClass) { * * @return The string containing the formatted class content */ - protected String buildClass() { + public String buildClass() { String formattedClass = "class " + pythonClass.getName() + ":"; if (!pythonClass.getMethods().isEmpty()) { formattedClass = formattedClass + "\n"; diff --git a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/FunctionAdapterContentBuilder.java b/server/src/main/java/com/larsreimann/api_editor/codegen/FunctionAdapterContentBuilder.java similarity index 89% rename from server/src/main/java/com/larsreimann/api_editor/server/file_handling/FunctionAdapterContentBuilder.java rename to server/src/main/java/com/larsreimann/api_editor/codegen/FunctionAdapterContentBuilder.java index 3a9d12d55..a4b3fcdde 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/FunctionAdapterContentBuilder.java +++ b/server/src/main/java/com/larsreimann/api_editor/codegen/FunctionAdapterContentBuilder.java @@ -1,14 +1,15 @@ -package com.larsreimann.api_editor.server.file_handling; +package com.larsreimann.api_editor.codegen; -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction; -import com.larsreimann.api_editor.server.data.AnnotatedPythonParameter; -import com.larsreimann.api_editor.server.data.PythonParameterAssignment; +import com.larsreimann.api_editor.io.FileBuilder; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonParameter; +import com.larsreimann.api_editor.model.PythonParameterAssignment; import java.util.ArrayList; import java.util.List; import java.util.Objects; -class FunctionAdapterContentBuilder extends FileBuilder { +public class FunctionAdapterContentBuilder extends FileBuilder { AnnotatedPythonFunction pythonFunction; /** @@ -16,7 +17,7 @@ class FunctionAdapterContentBuilder extends FileBuilder { * * @param pythonFunction The function whose adapter content should be built */ - protected FunctionAdapterContentBuilder( + public FunctionAdapterContentBuilder( AnnotatedPythonFunction pythonFunction ) { this.pythonFunction = pythonFunction; @@ -27,7 +28,7 @@ protected FunctionAdapterContentBuilder( * * @return The string containing the formatted function content */ - protected String buildFunction() { + public String buildFunction() { return "def " + pythonFunction.getName() + "(" @@ -64,13 +65,11 @@ private String buildFunctionParameters() { formattedFunctionParameters = formattedFunctionParameters + ", /, "; - } - else if(hasNameOnlyParameters) { + } else if (hasNameOnlyParameters) { formattedFunctionParameters = formattedFunctionParameters + ", /"; - } - else { + } else { formattedFunctionParameters = formattedFunctionParameters + ", /"; @@ -85,8 +84,7 @@ else if(hasNameOnlyParameters) { if (hasPositionOnlyParameters || hasPositionOrNameParameters) { formattedFunctionParameters = formattedFunctionParameters + ", *, "; - } - else { + } else { formattedFunctionParameters = formattedFunctionParameters + "*, "; } diff --git a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/ModuleAdapterContentBuilder.java b/server/src/main/java/com/larsreimann/api_editor/codegen/ModuleAdapterContentBuilder.java similarity index 92% rename from server/src/main/java/com/larsreimann/api_editor/server/file_handling/ModuleAdapterContentBuilder.java rename to server/src/main/java/com/larsreimann/api_editor/codegen/ModuleAdapterContentBuilder.java index ca8d323a7..04327fee4 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/ModuleAdapterContentBuilder.java +++ b/server/src/main/java/com/larsreimann/api_editor/codegen/ModuleAdapterContentBuilder.java @@ -1,13 +1,14 @@ -package com.larsreimann.api_editor.server.file_handling; +package com.larsreimann.api_editor.codegen; -import com.larsreimann.api_editor.server.data.AnnotatedPythonModule; +import com.larsreimann.api_editor.io.FileBuilder; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; -class ModuleAdapterContentBuilder extends FileBuilder { +public class ModuleAdapterContentBuilder extends FileBuilder { AnnotatedPythonModule pythonModule; /** @@ -15,7 +16,7 @@ class ModuleAdapterContentBuilder extends FileBuilder { * * @param pythonModule The module whose adapter content should be built */ - protected ModuleAdapterContentBuilder(AnnotatedPythonModule pythonModule) { + public ModuleAdapterContentBuilder(AnnotatedPythonModule pythonModule) { this.pythonModule = pythonModule; } @@ -24,7 +25,7 @@ protected ModuleAdapterContentBuilder(AnnotatedPythonModule pythonModule) { * * @return The string containing the formatted module content */ - protected String buildModuleContent() { + public String buildModuleContent() { String formattedImport = buildNamespace(); String formattedClasses = buildAllClasses(); String formattedFunctions = buildAllFunctions(); diff --git a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/FileBuilder.java b/server/src/main/java/com/larsreimann/api_editor/io/FileBuilder.java similarity index 93% rename from server/src/main/java/com/larsreimann/api_editor/server/file_handling/FileBuilder.java rename to server/src/main/java/com/larsreimann/api_editor/io/FileBuilder.java index ec06c52e2..4566d1f73 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/FileBuilder.java +++ b/server/src/main/java/com/larsreimann/api_editor/io/FileBuilder.java @@ -1,18 +1,18 @@ -package com.larsreimann.api_editor.server.file_handling; +package com.larsreimann.api_editor.io; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.List; import java.util.Locale; -abstract class FileBuilder { +public abstract class FileBuilder { /** * Returns an indented version of the passed string * * @param toIndent The string to be indented * @return The indented string */ - String indent(String toIndent) { + protected String indent(String toIndent) { String INDENTATION = " "; toIndent = INDENTATION + toIndent; toIndent = toIndent.replaceAll("\n", "\n" + INDENTATION); @@ -29,7 +29,7 @@ String indent(String toIndent) { * elements of the list * @return The string resulting from joining the list elements */ - String listToString( + protected String listToString( List listToConvert, int numberOfNewlines ) { String delimiter; @@ -69,9 +69,7 @@ private int countChars(String baseString, char charToCount) { * @param defaultValue The default value to format * @return The formatted default value */ - String buildFormattedDefaultValue( - String defaultValue - ) { + protected String buildFormattedDefaultValue(String defaultValue) { String invalid = "\"###invalid###" + defaultValue.replace("\"", "\\\"") + "###\""; if ( defaultValue.length() >= 2 && diff --git a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/PackageFileBuilder.java b/server/src/main/java/com/larsreimann/api_editor/io/PackageFileBuilder.java similarity index 91% rename from server/src/main/java/com/larsreimann/api_editor/server/file_handling/PackageFileBuilder.java rename to server/src/main/java/com/larsreimann/api_editor/io/PackageFileBuilder.java index 385d3f482..f1d291ed0 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/PackageFileBuilder.java +++ b/server/src/main/java/com/larsreimann/api_editor/io/PackageFileBuilder.java @@ -1,7 +1,9 @@ -package com.larsreimann.api_editor.server.file_handling; +package com.larsreimann.api_editor.io; -import com.larsreimann.api_editor.server.data.AnnotatedPythonModule; -import com.larsreimann.api_editor.server.data.AnnotatedPythonPackage; +import com.larsreimann.api_editor.codegen.ModuleAdapterContentBuilder; +import com.larsreimann.api_editor.codegen.ModuleStubContentBuilder; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonPackage; import kotlin.io.FilesKt; import java.io.BufferedWriter; @@ -20,7 +22,8 @@ public class PackageFileBuilder { /** * Constructor for PackageFileBuilder - * @param pythonPackage The package whose files should be generated + * + * @param pythonPackage The package whose files should be generated */ public PackageFileBuilder(AnnotatedPythonPackage pythonPackage) { this.pythonPackage = pythonPackage; diff --git a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/ClassStubContentBuilder.java b/server/src/main/java/com/larsreimann/api_editor/server/file_handling/ClassStubContentBuilder.java deleted file mode 100644 index 980d5785d..000000000 --- a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/ClassStubContentBuilder.java +++ /dev/null @@ -1,200 +0,0 @@ -package com.larsreimann.api_editor.server.file_handling; - -import com.larsreimann.api_editor.server.data.AnnotatedPythonClass; -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction; -import com.larsreimann.api_editor.server.data.AnnotatedPythonParameter; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -class ClassStubContentBuilder extends FileBuilder { - String className; - List classMethods; - boolean hasConstructor; - boolean hasClassMethods; - AnnotatedPythonFunction constructor; - - /** - * Constructor for ClassStubContentBuilder - * - * @param pythonClass The class whose stub content should be built - */ - protected ClassStubContentBuilder( - AnnotatedPythonClass pythonClass - ) { - List originalClassMethods = pythonClass.getMethods(); - this.hasConstructor = hasConstructor(originalClassMethods); - this.hasClassMethods = hasClassMethods(originalClassMethods); - this.className = pythonClass.getName(); - if (!hasConstructor) { - this.classMethods = originalClassMethods; - } - else { - this.classMethods = getClassMethods(originalClassMethods); - this.constructor = getConstructor(originalClassMethods); - } - } - - /** - * Builds a string containing the formatted class content - * - * @return The string containing the formatted class content - */ - protected String buildClass() { - String formattedClassCall = buildClassCall(); - String formattedClassBody = buildClassBody(); - return buildFormattedClass(formattedClassCall, formattedClassBody); - } - - private List getClassMethods( - List pythonFunctions - ) { - return pythonFunctions.stream() - .filter(pythonFunction -> - !pythonFunction.getName().equals("__init__")) - .collect(Collectors.toList()); - } - - private boolean hasClassMethods( - List pythonFunctions - ) { - return pythonFunctions - .stream() - .filter(pythonFunction -> - !pythonFunction.getName().equals("__init__")) - .findAny() - .orElse(null) != null; - } - - private boolean hasConstructor( - List pythonFunctions - ) { - return pythonFunctions - .stream() - .filter(pythonFunction -> - pythonFunction.getName().equals("__init__")) - .findAny() - .orElse(null) != null; - } - - private AnnotatedPythonFunction getConstructor( - List pythonFunctions - ) { - return pythonFunctions - .stream() - .filter(pythonFunction -> - pythonFunction.getName().equals("__init__")) - .findAny() - .orElse(null); - } - - private String buildClassCall() { - String formattedConstructorBody = ""; - if (hasConstructor) { - formattedConstructorBody = buildConstructor(constructor); - } - return "open class " - + className - + "(" - + formattedConstructorBody - + ")"; - } - - private String buildConstructor( - AnnotatedPythonFunction pythonFunction - ) { - List pythonParameters = pythonFunction.getParameters(); - if (pythonParameters.isEmpty()) { - return ""; - } - List formattedConstructorParameters = new ArrayList<>(); - pythonParameters.forEach(pythonParameter -> - formattedConstructorParameters.add( - buildConstructorParameter(pythonParameter) - )); - return String.join(", ", formattedConstructorParameters); - } - - private String buildConstructorParameter( - AnnotatedPythonParameter pythonParameter - ) { - String formattedParameter = pythonParameter.getName() + ": " + "Any?"; - String defaultValue = pythonParameter.getDefaultValue(); - if (defaultValue != null - && !defaultValue.isBlank()) { - formattedParameter = formattedParameter - + " or " - + buildFormattedDefaultValue(defaultValue); - } - return formattedParameter; - } - - private String buildClassBody() { - String formattedAttributes = ""; - if (hasConstructor) { - formattedAttributes = buildAttributes(); - } - String formattedFunctions = ""; - if (hasClassMethods) { - formattedFunctions = buildFunctions(); - } - if (formattedAttributes.isBlank()) { - if (formattedFunctions.isBlank()) { - return ""; - } - return formattedFunctions; - } - if (formattedFunctions.isBlank()) { - return formattedAttributes; - } - return formattedAttributes + "\n\n" + formattedFunctions; - } - - private String buildAttributes() { - List formattedAttributes = new ArrayList<>(); - constructor.getParameters().forEach(pythonParameter -> formattedAttributes.add( - "attr " - + pythonParameter.getName() - + ": " - + "Any?" - )); - return listToString(formattedAttributes, 1); - } - - private String buildFunctions() { - List formattedFunctions = new ArrayList<>(); - classMethods.forEach(pythonFunction -> { - String formattedFunction = ""; - if (isOverriding(pythonFunction)) { - formattedFunction = formattedFunction + "override "; - } - FunctionStubContentBuilder functionStubContentBuilder = - new FunctionStubContentBuilder(pythonFunction); - formattedFunction = formattedFunction - + functionStubContentBuilder.buildFunction(); - formattedFunctions.add( - formattedFunction - ); - }); - return listToString(formattedFunctions, 1); - } - - private boolean isOverriding(AnnotatedPythonFunction pythonFunction) { - // TODO - return false; - } - - private String buildFormattedClass( - String classCall, - String classBody - ) { - if (classBody.isBlank()) { - return classCall + " {}"; - } - return classCall - + " {\n" - + indent(classBody) - + "\n}"; - } -} diff --git a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/FunctionStubContentBuilder.java b/server/src/main/java/com/larsreimann/api_editor/server/file_handling/FunctionStubContentBuilder.java deleted file mode 100644 index 548261555..000000000 --- a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/FunctionStubContentBuilder.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.larsreimann.api_editor.server.file_handling; - -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction; -import com.larsreimann.api_editor.server.data.AnnotatedPythonParameter; -import com.larsreimann.api_editor.server.data.AnnotatedPythonResult; - -import java.util.ArrayList; -import java.util.List; - -class FunctionStubContentBuilder extends FileBuilder { - AnnotatedPythonFunction pythonFunction; - - /** - * Constructor for FunctionStubContentBuilder - * - * @param pythonFunction The function whose stub content should be built - */ - protected FunctionStubContentBuilder(AnnotatedPythonFunction pythonFunction) { - this.pythonFunction = pythonFunction; - } - - /** - * Builds a string containing the formatted function content - * - * @return The string containing the formatted function content - */ - protected String buildFunction() { - return buildPureAnnotation() - + "fun " - + pythonFunction.getName() - + "(" - + buildAllFunctionParameters() - + ")" - + buildAllFormattedResults(); - } - - private String buildPureAnnotation() { - if (this.pythonFunction.isPure()) { - return "@Pure\n"; - } else { - return ""; - } - } - - private String buildAllFunctionParameters() { - List pythonParameters = pythonFunction.getParameters(); - if (pythonParameters.isEmpty()) { - return ""; - } - List formattedFunctionParameters = new ArrayList<>(); - pythonParameters.forEach(pythonParameter -> - formattedFunctionParameters - .add(buildFormattedParameter(pythonParameter))); - return String.join(", ", formattedFunctionParameters); - } - - private String buildFormattedParameter( - AnnotatedPythonParameter pythonParameter - ) { - String formattedParameter = pythonParameter.getName() + ": " + "Any?"; - String defaultValue = pythonParameter.getDefaultValue(); - if (defaultValue != null - && !defaultValue.isBlank()) { - formattedParameter = formattedParameter - + " or " - + buildFormattedDefaultValue(defaultValue); - } - return formattedParameter; - } - - private String buildAllFormattedResults() { - List pythonResults = pythonFunction.getResults(); - if (pythonResults.isEmpty()) { - return ""; - } - if (pythonResults.size() == 1) { - return " -> " - + buildFormattedResult(pythonResults.get(0)); - } else { - List formattedResults = new ArrayList<>(); - pythonResults.forEach(pythonResult -> formattedResults - .add(buildFormattedResult(pythonResult))); - String resultsAsString = String.join(", ", formattedResults); - return " -> [" + resultsAsString + "]"; - } - } - - private String buildFormattedResult( - AnnotatedPythonResult pythonResult - ) { - return pythonResult.getName() - + ": " - + pythonResult.getType(); - } -} diff --git a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/ModuleStubContentBuilder.java b/server/src/main/java/com/larsreimann/api_editor/server/file_handling/ModuleStubContentBuilder.java deleted file mode 100644 index a8e312cba..000000000 --- a/server/src/main/java/com/larsreimann/api_editor/server/file_handling/ModuleStubContentBuilder.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.larsreimann.api_editor.server.file_handling; - -import com.larsreimann.api_editor.server.data.AnnotatedPythonModule; - -import java.util.ArrayList; -import java.util.List; - -class ModuleStubContentBuilder extends FileBuilder { - AnnotatedPythonModule pythonModule; - - /** - * Constructor for ModuleStubContentBuilder - * - * @param pythonModule The module whose stub content should be built - */ - protected ModuleStubContentBuilder(AnnotatedPythonModule pythonModule) { - this.pythonModule = pythonModule; - } - - /** - * Builds a string containing the formatted module content - * - * @return The string containing the formatted module content - */ - protected String buildModuleContent() { - String formattedPackageDeclaration = buildPackageDeclaration(); - String formattedClasses = buildAllClasses(); - String formattedFunctions = buildAllFunctions(); - String[] separators = buildSeparators( - formattedPackageDeclaration, - formattedClasses, - formattedFunctions - ); - formattedPackageDeclaration = formattedPackageDeclaration + separators[0]; - formattedClasses = formattedClasses + separators[1]; - formattedFunctions = formattedFunctions + separators[2]; - - return formattedPackageDeclaration - + formattedClasses - + formattedFunctions; - } - - private String buildPackageDeclaration() { - return "package " - + "simpleml." - + pythonModule.getName(); - } - - private String buildAllClasses() { - List formattedClasses = new ArrayList<>(); - pythonModule.getClasses().forEach(pythonClass -> { - ClassStubContentBuilder classStubContentBuilder = - new ClassStubContentBuilder(pythonClass); - formattedClasses.add(classStubContentBuilder.buildClass()); - }); - return listToString(formattedClasses, 2); - } - - private String buildAllFunctions() { - List formattedFunctions = new ArrayList<>(); - pythonModule.getFunctions().forEach(pythonFunction -> { - FunctionStubContentBuilder functionStubContentBuilder = - new FunctionStubContentBuilder(pythonFunction); - formattedFunctions.add(functionStubContentBuilder.buildFunction()); - } - ); - return listToString(formattedFunctions, 2); - } - - private String[] buildSeparators( - String formattedPackageDeclaration, - String formattedClasses, - String formattedFunctions - ) { - String packageDeclarationSeparator; - if (formattedPackageDeclaration.isBlank()) { - packageDeclarationSeparator = ""; - } else if (formattedClasses.isBlank() && formattedFunctions.isBlank()) { - packageDeclarationSeparator = "\n"; - } else { - packageDeclarationSeparator = "\n\n"; - } - String classesSeparator; - if (formattedClasses.isBlank()) { - classesSeparator = ""; - } else if (formattedFunctions.isBlank()) { - classesSeparator = "\n"; - } else { - classesSeparator = "\n\n"; - } - String functionSeparator; - if (formattedFunctions.isBlank()) { - functionSeparator = ""; - } else { - functionSeparator = "\n"; - } - - return new String[]{packageDeclarationSeparator, classesSeparator, functionSeparator}; - } -} diff --git a/server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/CleanupModulesProcessor.java b/server/src/main/java/com/larsreimann/api_editor/transformation/CleanupModulesProcessor.java similarity index 77% rename from server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/CleanupModulesProcessor.java rename to server/src/main/java/com/larsreimann/api_editor/transformation/CleanupModulesProcessor.java index 41057bf71..a7d4b7c05 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/CleanupModulesProcessor.java +++ b/server/src/main/java/com/larsreimann/api_editor/transformation/CleanupModulesProcessor.java @@ -1,9 +1,16 @@ -package com.larsreimann.api_editor.server.annotationProcessing; +package com.larsreimann.api_editor.transformation; -import com.larsreimann.api_editor.server.data.*; +import com.larsreimann.api_editor.model.AbstractPackageDataVisitor; +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonPackage; import org.jetbrains.annotations.NotNull; -import static com.larsreimann.api_editor.server.util.PackageDataFactoriesKt.*; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createClassCopyWithoutFunctions; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createFunctionCopy; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createModuleCopyWithoutClassesAndFunctions; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createPackageCopyWithoutModules; public class CleanupModulesProcessor extends AbstractPackageDataVisitor { private AnnotatedPythonPackage modifiedPackage; diff --git a/server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/MoveAnnotationProcessor.java b/server/src/main/java/com/larsreimann/api_editor/transformation/MoveAnnotationProcessor.java similarity index 89% rename from server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/MoveAnnotationProcessor.java rename to server/src/main/java/com/larsreimann/api_editor/transformation/MoveAnnotationProcessor.java index 9ea73ad1a..e050a52f8 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/MoveAnnotationProcessor.java +++ b/server/src/main/java/com/larsreimann/api_editor/transformation/MoveAnnotationProcessor.java @@ -1,13 +1,25 @@ -package com.larsreimann.api_editor.server.annotationProcessing; - -import com.larsreimann.api_editor.server.data.*; +package com.larsreimann.api_editor.transformation; + +import com.larsreimann.api_editor.model.AbstractPackageDataVisitor; +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonPackage; +import com.larsreimann.api_editor.model.AnnotatedPythonParameter; +import com.larsreimann.api_editor.model.EditorAnnotation; +import com.larsreimann.api_editor.model.MoveAnnotation; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; -import static com.larsreimann.api_editor.server.util.PackageDataFactoriesKt.*; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonClass; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonFunction; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonModule; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonParameter; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createModuleCopyWithoutClassesAndFunctions; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createPackageCopyWithoutModules; public class MoveAnnotationProcessor extends AbstractPackageDataVisitor { private AnnotatedPythonPackage modifiedPackage; @@ -109,8 +121,7 @@ public boolean enterPythonClass(@NotNull AnnotatedPythonClass pythonClass) { originalModuleName = qualifiedNameGenerator.currentModuleName; newModuleName = ((MoveAnnotation) editorAnnotation).getDestination(); qualifiedNameGenerator.currentModuleName = newModuleName; - } - else { + } else { annotations.add(editorAnnotation); } } @@ -129,8 +140,7 @@ public boolean enterPythonClass(@NotNull AnnotatedPythonClass pythonClass) { if (isClassMoved) { addClassToAdd(newModuleName, currentClass); - } - else { + } else { currentModule.getClasses().add(currentClass); } @@ -181,8 +191,7 @@ public boolean enterPythonFunction(AnnotatedPythonFunction pythonFunction) { originalModuleName = qualifiedNameGenerator.currentModuleName; newModuleName = ((MoveAnnotation) editorAnnotation).getDestination(); qualifiedNameGenerator.currentModuleName = newModuleName; - } - else { + } else { annotations.add(editorAnnotation); } } diff --git a/server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/RenameAnnotationProcessor.java b/server/src/main/java/com/larsreimann/api_editor/transformation/RenameAnnotationProcessor.java similarity index 54% rename from server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/RenameAnnotationProcessor.java rename to server/src/main/java/com/larsreimann/api_editor/transformation/RenameAnnotationProcessor.java index ebb508093..c83ad7737 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/RenameAnnotationProcessor.java +++ b/server/src/main/java/com/larsreimann/api_editor/transformation/RenameAnnotationProcessor.java @@ -1,11 +1,22 @@ -package com.larsreimann.api_editor.server.annotationProcessing; - -import com.larsreimann.api_editor.server.data.*; +package com.larsreimann.api_editor.transformation; + +import com.larsreimann.api_editor.model.AbstractPackageDataVisitor; +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonPackage; +import com.larsreimann.api_editor.model.AnnotatedPythonParameter; +import com.larsreimann.api_editor.model.EditorAnnotation; +import com.larsreimann.api_editor.model.RenameAnnotation; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -import static com.larsreimann.api_editor.server.util.PackageDataFactoriesKt.*; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonClass; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonFunction; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonParameter; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createModuleCopyWithoutClassesAndFunctions; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createPackageCopyWithoutModules; public class RenameAnnotationProcessor extends AbstractPackageDataVisitor { private AnnotatedPythonPackage modifiedPackage; @@ -14,7 +25,7 @@ public class RenameAnnotationProcessor extends AbstractPackageDataVisitor { private AnnotatedPythonClass currentClass; private AnnotatedPythonFunction currentFunction; private final QualifiedNameGenerator qualifiedNameGenerator = - new QualifiedNameGenerator(); + new QualifiedNameGenerator(); private boolean inFunction = false; private boolean inClass = false; private boolean inModule = false; @@ -58,30 +69,29 @@ public boolean enterPythonClass(@NotNull AnnotatedPythonClass pythonClass) { qualifiedNameGenerator.currentClassName = pythonClass.getName(); ArrayList annotations = new ArrayList<>(); pythonClass - .getAnnotations() - .forEach( - editorAnnotation -> { - if (editorAnnotation instanceof RenameAnnotation) { - qualifiedNameGenerator.currentClassName = - ((RenameAnnotation) editorAnnotation) - .getNewName(); - } - else { - annotations.add(editorAnnotation); - } - } - ); + .getAnnotations() + .forEach( + editorAnnotation -> { + if (editorAnnotation instanceof RenameAnnotation) { + qualifiedNameGenerator.currentClassName = + ((RenameAnnotation) editorAnnotation) + .getNewName(); + } else { + annotations.add(editorAnnotation); + } + } + ); currentClass = createAnnotatedPythonClass( - qualifiedNameGenerator.currentClassName, - qualifiedNameGenerator.getQualifiedClassName(), - new ArrayList<>(pythonClass.getDecorators()), - new ArrayList<>(pythonClass.getSuperclasses()), - new ArrayList<>(), - pythonClass.getDescription(), - pythonClass.getFullDocstring(), - annotations, - pythonClass.getOriginalDeclaration() + qualifiedNameGenerator.currentClassName, + qualifiedNameGenerator.getQualifiedClassName(), + new ArrayList<>(pythonClass.getDecorators()), + new ArrayList<>(pythonClass.getSuperclasses()), + new ArrayList<>(), + pythonClass.getDescription(), + pythonClass.getFullDocstring(), + annotations, + pythonClass.getOriginalDeclaration() ); if (inModule) { @@ -101,32 +111,31 @@ public void enterPythonParameter(AnnotatedPythonParameter pythonParameter) { qualifiedNameGenerator.currentParameterName = pythonParameter.getName(); ArrayList annotations = new ArrayList<>(); pythonParameter - .getAnnotations() - .forEach( - editorAnnotation -> { - if (editorAnnotation instanceof RenameAnnotation) { - qualifiedNameGenerator.currentParameterName = - ((RenameAnnotation) editorAnnotation) - .getNewName(); - } - else { - annotations.add(editorAnnotation); - } - } - ); + .getAnnotations() + .forEach( + editorAnnotation -> { + if (editorAnnotation instanceof RenameAnnotation) { + qualifiedNameGenerator.currentParameterName = + ((RenameAnnotation) editorAnnotation) + .getNewName(); + } else { + annotations.add(editorAnnotation); + } + } + ); AnnotatedPythonParameter modifiedPythonParameter = - createAnnotatedPythonParameter( - qualifiedNameGenerator.currentParameterName, - qualifiedNameGenerator.getQualifiedParameterName(), - pythonParameter.getDefaultValue(), - pythonParameter.getAssignedBy(), - pythonParameter.isPublic(), - pythonParameter.getTypeInDocs(), - pythonParameter.getDescription(), - annotations, - pythonParameter.getOriginalDeclaration() - ); + createAnnotatedPythonParameter( + qualifiedNameGenerator.currentParameterName, + qualifiedNameGenerator.getQualifiedParameterName(), + pythonParameter.getDefaultValue(), + pythonParameter.getAssignedBy(), + pythonParameter.isPublic(), + pythonParameter.getTypeInDocs(), + pythonParameter.getDescription(), + annotations, + pythonParameter.getOriginalDeclaration() + ); if (inFunction) { currentFunction.getParameters().add(modifiedPythonParameter); @@ -139,31 +148,30 @@ public boolean enterPythonFunction(AnnotatedPythonFunction pythonFunction) { qualifiedNameGenerator.currentFunctionName = pythonFunction.getName(); ArrayList annotations = new ArrayList<>(); pythonFunction - .getAnnotations() - .forEach( - editorAnnotation -> { - if (editorAnnotation instanceof RenameAnnotation) { - qualifiedNameGenerator.currentFunctionName = - ((RenameAnnotation) editorAnnotation) - .getNewName(); - } - else { - annotations.add(editorAnnotation); - } - } - ); + .getAnnotations() + .forEach( + editorAnnotation -> { + if (editorAnnotation instanceof RenameAnnotation) { + qualifiedNameGenerator.currentFunctionName = + ((RenameAnnotation) editorAnnotation) + .getNewName(); + } else { + annotations.add(editorAnnotation); + } + } + ); currentFunction = createAnnotatedPythonFunction( - qualifiedNameGenerator.currentFunctionName, - qualifiedNameGenerator.getQualifiedFunctionName(), - new ArrayList<>(pythonFunction.getDecorators()), - new ArrayList<>(), - new ArrayList<>(pythonFunction.getResults()), - pythonFunction.isPublic(), - pythonFunction.getDescription(), - pythonFunction.getFullDocstring(), - annotations, - pythonFunction.getOriginalDeclaration() + qualifiedNameGenerator.currentFunctionName, + qualifiedNameGenerator.getQualifiedFunctionName(), + new ArrayList<>(pythonFunction.getDecorators()), + new ArrayList<>(), + new ArrayList<>(pythonFunction.getResults()), + pythonFunction.isPublic(), + pythonFunction.getDescription(), + pythonFunction.getFullDocstring(), + annotations, + pythonFunction.getOriginalDeclaration() ); if (inClass) { diff --git a/server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/UnusedAnnotationProcessor.java b/server/src/main/java/com/larsreimann/api_editor/transformation/UnusedAnnotationProcessor.java similarity index 79% rename from server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/UnusedAnnotationProcessor.java rename to server/src/main/java/com/larsreimann/api_editor/transformation/UnusedAnnotationProcessor.java index 755580d4f..394a43a41 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/annotationProcessing/UnusedAnnotationProcessor.java +++ b/server/src/main/java/com/larsreimann/api_editor/transformation/UnusedAnnotationProcessor.java @@ -1,9 +1,16 @@ -package com.larsreimann.api_editor.server.annotationProcessing; +package com.larsreimann.api_editor.transformation; -import com.larsreimann.api_editor.server.data.*; +import com.larsreimann.api_editor.model.AbstractPackageDataVisitor; +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonPackage; import org.jetbrains.annotations.NotNull; -import static com.larsreimann.api_editor.server.util.PackageDataFactoriesKt.*; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createClassCopyWithoutFunctions; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createFunctionCopy; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createModuleCopyWithoutClassesAndFunctions; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createPackageCopyWithoutModules; public class UnusedAnnotationProcessor extends AbstractPackageDataVisitor { private AnnotatedPythonPackage modifiedPackage; diff --git a/server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationCombinationError.java b/server/src/main/java/com/larsreimann/api_editor/validation/AnnotationCombinationError.java similarity index 90% rename from server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationCombinationError.java rename to server/src/main/java/com/larsreimann/api_editor/validation/AnnotationCombinationError.java index 84ca6bc5a..06f531133 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationCombinationError.java +++ b/server/src/main/java/com/larsreimann/api_editor/validation/AnnotationCombinationError.java @@ -1,4 +1,4 @@ -package com.larsreimann.api_editor.server.validation; +package com.larsreimann.api_editor.validation; public record AnnotationCombinationError( String qualifiedName, diff --git a/server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationError.java b/server/src/main/java/com/larsreimann/api_editor/validation/AnnotationError.java similarity index 78% rename from server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationError.java rename to server/src/main/java/com/larsreimann/api_editor/validation/AnnotationError.java index 110f3377b..ef07dc69e 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationError.java +++ b/server/src/main/java/com/larsreimann/api_editor/validation/AnnotationError.java @@ -1,4 +1,4 @@ -package com.larsreimann.api_editor.server.validation; +package com.larsreimann.api_editor.validation; public interface AnnotationError { /** diff --git a/server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationTargetError.java b/server/src/main/java/com/larsreimann/api_editor/validation/AnnotationTargetError.java similarity index 81% rename from server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationTargetError.java rename to server/src/main/java/com/larsreimann/api_editor/validation/AnnotationTargetError.java index 0ce9ca276..09f9d3dbd 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationTargetError.java +++ b/server/src/main/java/com/larsreimann/api_editor/validation/AnnotationTargetError.java @@ -1,6 +1,6 @@ -package com.larsreimann.api_editor.server.validation; +package com.larsreimann.api_editor.validation; -import com.larsreimann.api_editor.server.data.AnnotationTarget; +import com.larsreimann.api_editor.model.AnnotationTarget; public record AnnotationTargetError( String qualifiedName, diff --git a/server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationValidator.java b/server/src/main/java/com/larsreimann/api_editor/validation/AnnotationValidator.java similarity index 94% rename from server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationValidator.java rename to server/src/main/java/com/larsreimann/api_editor/validation/AnnotationValidator.java index 4d7ead04e..9bf1b5bae 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/validation/AnnotationValidator.java +++ b/server/src/main/java/com/larsreimann/api_editor/validation/AnnotationValidator.java @@ -1,13 +1,13 @@ -package com.larsreimann.api_editor.server.validation; +package com.larsreimann.api_editor.validation; -import com.larsreimann.api_editor.server.data.AnnotatedPythonClass; -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction; -import com.larsreimann.api_editor.server.data.AnnotatedPythonModule; -import com.larsreimann.api_editor.server.data.AnnotatedPythonPackage; -import com.larsreimann.api_editor.server.data.AnnotatedPythonParameter; -import com.larsreimann.api_editor.server.data.AnnotationTarget; -import com.larsreimann.api_editor.server.data.EditorAnnotation; -import com.larsreimann.api_editor.server.data.GroupAnnotation; +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonPackage; +import com.larsreimann.api_editor.model.AnnotatedPythonParameter; +import com.larsreimann.api_editor.model.AnnotationTarget; +import com.larsreimann.api_editor.model.EditorAnnotation; +import com.larsreimann.api_editor.model.GroupAnnotation; import java.util.ArrayList; import java.util.Collections; diff --git a/server/src/main/java/com/larsreimann/api_editor/server/validation/GroupAnnotationCombinationError.java b/server/src/main/java/com/larsreimann/api_editor/validation/GroupAnnotationCombinationError.java similarity index 90% rename from server/src/main/java/com/larsreimann/api_editor/server/validation/GroupAnnotationCombinationError.java rename to server/src/main/java/com/larsreimann/api_editor/validation/GroupAnnotationCombinationError.java index 79e91d69b..d7cddddd7 100644 --- a/server/src/main/java/com/larsreimann/api_editor/server/validation/GroupAnnotationCombinationError.java +++ b/server/src/main/java/com/larsreimann/api_editor/validation/GroupAnnotationCombinationError.java @@ -1,4 +1,4 @@ -package com.larsreimann.api_editor.server.validation; +package com.larsreimann.api_editor.validation; public record GroupAnnotationCombinationError( String qualifiedName, diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/codegen/ClassStubContentBuilder.kt b/server/src/main/kotlin/com/larsreimann/api_editor/codegen/ClassStubContentBuilder.kt new file mode 100644 index 000000000..aebce697e --- /dev/null +++ b/server/src/main/kotlin/com/larsreimann/api_editor/codegen/ClassStubContentBuilder.kt @@ -0,0 +1,141 @@ +package com.larsreimann.api_editor.codegen + +import com.larsreimann.api_editor.io.FileBuilder +import com.larsreimann.api_editor.model.AnnotatedPythonClass +import com.larsreimann.api_editor.model.AnnotatedPythonFunction +import com.larsreimann.api_editor.model.AnnotatedPythonParameter +import java.util.function.Consumer + +/** + * Constructor for ClassStubContentBuilder + * + * @param pythonClass The class whose stub content should be built + */ +class ClassStubContentBuilder( + private val pythonClass: AnnotatedPythonClass +) : FileBuilder() { + var classMethods: List + var hasConstructor: Boolean + var hasClassMethods: Boolean + var constructor: AnnotatedPythonFunction? = null + + init { + val originalClassMethods = pythonClass.methods + hasConstructor = hasConstructor() + hasClassMethods = hasClassMethods() + if (!hasConstructor) { + classMethods = originalClassMethods + } else { + classMethods = classMethods() + constructor = constructorOrNull() + } + } + + /** + * Builds a string containing the formatted class content + * + * @return The string containing the formatted class content + */ + fun buildClass(): String { + val formattedClassCall = buildClassCall() + val formattedClassBody = buildClassBody() + return when { + formattedClassBody.isBlank() -> "$formattedClassCall {}" + else -> """ + |$formattedClassCall { + |${indent(formattedClassBody)} + |} + """.trimMargin() + } + } + + private fun classMethods(): List { + return pythonClass.methods.filter { it.name != "__init__" } + } + + private fun hasClassMethods(): Boolean { + return pythonClass.methods.any { it.name != "__init__" } + } + + private fun hasConstructor(): Boolean { + return pythonClass.methods.any { it.name == "__init__" } + } + + private fun constructorOrNull(): AnnotatedPythonFunction? { + return pythonClass.methods.firstOrNull { it.name == "__init__" } + } + + private fun buildClassCall(): String { + val formattedConstructorBody = when { + hasConstructor() -> buildConstructor(constructor) + else -> "" + } + return "class ${pythonClass.name}($formattedConstructorBody)" + } + + private fun buildConstructor( + pythonFunction: AnnotatedPythonFunction? + ): String { + val pythonParameters = pythonFunction!!.parameters + if (pythonParameters.isEmpty()) { + return "" + } + val formattedConstructorParameters: MutableList = ArrayList() + pythonParameters.forEach( + Consumer { pythonParameter: AnnotatedPythonParameter -> + formattedConstructorParameters.add( + buildConstructorParameter(pythonParameter) + ) + } + ) + return java.lang.String.join(", ", formattedConstructorParameters) + } + + private fun buildConstructorParameter( + pythonParameter: AnnotatedPythonParameter + ): String { + val nameAndType = "${pythonParameter.name}: Any?" + val defaultValue = when { + pythonParameter.defaultValue.isNullOrBlank() -> "" + else -> " or ${buildFormattedDefaultValue(pythonParameter.defaultValue)}" + } + + return "$nameAndType$defaultValue" + } + + private fun buildClassBody(): String { + var formattedAttributes = "" + if (hasConstructor) { + formattedAttributes = buildAttributes() + } + var formattedFunctions = "" + if (hasClassMethods) { + formattedFunctions = buildFunctions() + } + if (formattedAttributes.isBlank()) { + return formattedFunctions.ifBlank { + "" + } + } + return if (formattedFunctions.isBlank()) { + formattedAttributes + } else """ + $formattedAttributes + + $formattedFunctions + """.trimIndent() + } + + private fun buildAttributes(): String { + return constructorOrNull() + ?.parameters + ?.joinToString { "attr ${it.name}: Any?" } + ?: "" + } + + private fun buildFunctions(): String { + return classMethods.joinToString(separator = "\n") { + FunctionStubContentBuilder(it).buildFunction() + } + } +} diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/codegen/FunctionStubContentBuilder.kt b/server/src/main/kotlin/com/larsreimann/api_editor/codegen/FunctionStubContentBuilder.kt new file mode 100644 index 000000000..c242d7c9b --- /dev/null +++ b/server/src/main/kotlin/com/larsreimann/api_editor/codegen/FunctionStubContentBuilder.kt @@ -0,0 +1,141 @@ +package com.larsreimann.api_editor.codegen + +import com.larsreimann.api_editor.io.FileBuilder +import com.larsreimann.api_editor.model.AnnotatedPythonFunction +import com.larsreimann.api_editor.model.AnnotatedPythonParameter +import com.larsreimann.api_editor.model.AnnotatedPythonResult +import de.unibonn.simpleml.constant.FileExtension +import de.unibonn.simpleml.emf.createSmlAnnotationUse +import de.unibonn.simpleml.emf.createSmlBoolean +import de.unibonn.simpleml.emf.createSmlClass +import de.unibonn.simpleml.emf.createSmlCompilationUnit +import de.unibonn.simpleml.emf.createSmlDummyResource +import de.unibonn.simpleml.emf.createSmlFloat +import de.unibonn.simpleml.emf.createSmlFunction +import de.unibonn.simpleml.emf.createSmlInt +import de.unibonn.simpleml.emf.createSmlNamedType +import de.unibonn.simpleml.emf.createSmlNull +import de.unibonn.simpleml.emf.createSmlParameter +import de.unibonn.simpleml.emf.createSmlResult +import de.unibonn.simpleml.emf.createSmlString +import de.unibonn.simpleml.serializer.SerializationResult +import de.unibonn.simpleml.serializer.serializeToFormattedString +import de.unibonn.simpleml.simpleML.SmlAbstractExpression +import de.unibonn.simpleml.simpleML.SmlAbstractType +import de.unibonn.simpleml.simpleML.SmlParameter +import de.unibonn.simpleml.simpleML.SmlResult + +/** + * Constructor for FunctionStubContentBuilder + * + * @param pythonFunction The function whose stub content should be built + */ +class FunctionStubContentBuilder(var pythonFunction: AnnotatedPythonFunction) : FileBuilder() { + + /** + * Builds a string containing the formatted function content + * + * @return The string containing the formatted function content + */ + fun buildFunction(): String { + val function = createSmlFunction( + name = pythonFunction.name, + annotations = buildList { + if (pythonFunction.isPure) { + add(createSmlAnnotationUse("Pure")) + } + }, + parameters = pythonFunction.parameters.map { buildParameter(it) }, + results = if (pythonFunction.results.isEmpty()) { + null + } else { + pythonFunction.results.map { buildResult(it) } + } + ) + + // Required to serialize the function + createSmlDummyResource( + "functionStub", + FileExtension.STUB, + createSmlCompilationUnit { + this.members += function + } + ) + + return when (val result = function.serializeToFormattedString()) { + is SerializationResult.Success -> result.code + is SerializationResult.Failure -> throw IllegalStateException(result.message) + } + } + + private fun buildParameter(pythonParameter: AnnotatedPythonParameter): SmlParameter { + return createSmlParameter( + name = pythonParameter.name, + type = buildSmlType(pythonParameter.typeInDocs), + defaultValue = pythonParameter.defaultValue?.let { buildDefaultValue(it) } + ) + } + + private fun buildResult(pythonResult: AnnotatedPythonResult): SmlResult { + return createSmlResult( + name = pythonResult.name, + type = buildSmlType(pythonResult.type) + ) + } + + private fun buildSmlType(pythonType: String): SmlAbstractType { + // TODO: create the correct type + return when (pythonType) { + "bool" -> createSmlNamedType( + declaration = createSmlClass("Boolean") + ) + "float" -> createSmlNamedType( + declaration = createSmlClass("Float") + ) + "int" -> createSmlNamedType( + declaration = createSmlClass("Int") + ) + "str" -> createSmlNamedType( + declaration = createSmlClass("String") + ) + else -> createSmlNamedType( + declaration = createSmlClass("Any"), + isNullable = true + ) + } + } + + /** + * Converts the given default value string to a formatted version that + * matches stub file convention + * + * @param defaultValue The default value to format + * @return The formatted default value + */ + fun buildDefaultValue(defaultValue: String): SmlAbstractExpression { + val invalid = "###invalid###" + defaultValue.replace("\"", "\\\"") + "###" + if (defaultValue.length >= 2 && ( + defaultValue[defaultValue.length - 1] + == defaultValue[0] + ) && defaultValue[0] == '\'' && defaultValue.count { it == '\'' } == 2 + ) { + return createSmlString(defaultValue.replace("'".toRegex(), "\"").trim('\'', '"')) + } + if (defaultValue == "False" || defaultValue == "True") { + return createSmlBoolean(defaultValue == "True") + } + if (defaultValue == "None") { + return createSmlNull() + } + try { + val numericValue = defaultValue.toDouble() + if (numericValue.toInt().toDouble() == numericValue) { + return createSmlInt(numericValue.toInt()) + } + return createSmlFloat(numericValue) + } catch (e: NumberFormatException) { + // do nothing if defaultValue is not numeric + } + return createSmlString(invalid) + } +} diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/codegen/ModuleStubContentBuilder.kt b/server/src/main/kotlin/com/larsreimann/api_editor/codegen/ModuleStubContentBuilder.kt new file mode 100644 index 000000000..5ed863965 --- /dev/null +++ b/server/src/main/kotlin/com/larsreimann/api_editor/codegen/ModuleStubContentBuilder.kt @@ -0,0 +1,94 @@ +package com.larsreimann.api_editor.codegen + +import com.larsreimann.api_editor.io.FileBuilder +import com.larsreimann.api_editor.model.AnnotatedPythonClass +import com.larsreimann.api_editor.model.AnnotatedPythonFunction +import com.larsreimann.api_editor.model.AnnotatedPythonModule +import java.util.function.Consumer + +class ModuleStubContentBuilder +/** + * Constructor for ModuleStubContentBuilder + * + * @param pythonModule The module whose stub content should be built + */(var pythonModule: AnnotatedPythonModule) : FileBuilder() { + /** + * Builds a string containing the formatted module content + * + * @return The string containing the formatted module content + */ + fun buildModuleContent(): String { + var formattedPackageDeclaration = buildPackageDeclaration() + var formattedClasses = buildAllClasses() + var formattedFunctions = buildAllFunctions() + val separators = buildSeparators( + formattedPackageDeclaration, + formattedClasses, + formattedFunctions + ) + formattedPackageDeclaration += separators[0] + formattedClasses += separators[1] + formattedFunctions += separators[2] + return ( + formattedPackageDeclaration + + formattedClasses + + formattedFunctions + ) + } + + private fun buildPackageDeclaration(): String { + return ( + "package " + + "simpleml." + + pythonModule.name + ) + } + + private fun buildAllClasses(): String { + val formattedClasses: MutableList = ArrayList() + pythonModule.classes.forEach( + Consumer { pythonClass: AnnotatedPythonClass? -> + val classStubContentBuilder = ClassStubContentBuilder( + pythonClass!! + ) + formattedClasses.add(classStubContentBuilder.buildClass()) + } + ) + return listToString(formattedClasses, 2) + } + + private fun buildAllFunctions(): String { + val formattedFunctions: MutableList = ArrayList() + pythonModule.functions.forEach( + Consumer { pythonFunction: AnnotatedPythonFunction? -> + val functionStubContentBuilder = FunctionStubContentBuilder( + pythonFunction!! + ) + formattedFunctions.add(functionStubContentBuilder.buildFunction()) + } + ) + return listToString(formattedFunctions, 2) + } + + private fun buildSeparators( + formattedPackageDeclaration: String, + formattedClasses: String, + formattedFunctions: String + ): Array { + val packageDeclarationSeparator: String = when { + formattedPackageDeclaration.isBlank() -> "" + formattedClasses.isBlank() && formattedFunctions.isBlank() -> "\n" + else -> "\n\n" + } + val classesSeparator: String = when { + formattedClasses.isBlank() -> "" + formattedFunctions.isBlank() -> "\n" + else -> "\n\n" + } + val functionSeparator: String = when { + formattedFunctions.isBlank() -> "" + else -> "\n" + } + return arrayOf(packageDeclarationSeparator, classesSeparator, functionSeparator) + } +} diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/server/data/PackageDataVisitor.kt b/server/src/main/kotlin/com/larsreimann/api_editor/model/PackageDataVisitor.kt similarity index 98% rename from server/src/main/kotlin/com/larsreimann/api_editor/server/data/PackageDataVisitor.kt rename to server/src/main/kotlin/com/larsreimann/api_editor/model/PackageDataVisitor.kt index d92423246..1f1339760 100644 --- a/server/src/main/kotlin/com/larsreimann/api_editor/server/data/PackageDataVisitor.kt +++ b/server/src/main/kotlin/com/larsreimann/api_editor/model/PackageDataVisitor.kt @@ -1,4 +1,4 @@ -package com.larsreimann.api_editor.server.data +package com.larsreimann.api_editor.model interface PackageDataVisitor { diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/server/data/editorAnnotations.kt b/server/src/main/kotlin/com/larsreimann/api_editor/model/editorAnnotations.kt similarity index 85% rename from server/src/main/kotlin/com/larsreimann/api_editor/server/data/editorAnnotations.kt rename to server/src/main/kotlin/com/larsreimann/api_editor/model/editorAnnotations.kt index 932163a74..5af397ab3 100644 --- a/server/src/main/kotlin/com/larsreimann/api_editor/server/data/editorAnnotations.kt +++ b/server/src/main/kotlin/com/larsreimann/api_editor/model/editorAnnotations.kt @@ -1,10 +1,10 @@ -package com.larsreimann.api_editor.server.data +package com.larsreimann.api_editor.model -import com.larsreimann.api_editor.server.data.AnnotationTarget.CLASS -import com.larsreimann.api_editor.server.data.AnnotationTarget.CONSTRUCTOR_PARAMETER -import com.larsreimann.api_editor.server.data.AnnotationTarget.FUNCTION_PARAMETER -import com.larsreimann.api_editor.server.data.AnnotationTarget.GLOBAL_FUNCTION -import com.larsreimann.api_editor.server.data.AnnotationTarget.METHOD +import com.larsreimann.api_editor.model.AnnotationTarget.CLASS +import com.larsreimann.api_editor.model.AnnotationTarget.CONSTRUCTOR_PARAMETER +import com.larsreimann.api_editor.model.AnnotationTarget.FUNCTION_PARAMETER +import com.larsreimann.api_editor.model.AnnotationTarget.GLOBAL_FUNCTION +import com.larsreimann.api_editor.model.AnnotationTarget.METHOD import kotlinx.serialization.Serializable import kotlinx.serialization.Transient @@ -115,7 +115,10 @@ object RequiredAnnotation : EditorAnnotation() { object UnusedAnnotation : EditorAnnotation() { @Transient - override val validTargets = setOf(CLASS, GLOBAL_FUNCTION, METHOD) + override val validTargets = setOf( + CLASS, + GLOBAL_FUNCTION, METHOD + ) } @Serializable @@ -145,4 +148,7 @@ enum class AnnotationTarget(private val target: String) { val GLOBAL_DECLARATIONS = setOf(CLASS, GLOBAL_FUNCTION) val CLASSES = setOf(CLASS) val FUNCTIONS = setOf(GLOBAL_FUNCTION, METHOD) -val PARAMETERS = setOf(CONSTRUCTOR_PARAMETER, FUNCTION_PARAMETER) +val PARAMETERS = setOf( + CONSTRUCTOR_PARAMETER, + FUNCTION_PARAMETER +) diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/server/data/packageData.kt b/server/src/main/kotlin/com/larsreimann/api_editor/model/packageData.kt similarity index 99% rename from server/src/main/kotlin/com/larsreimann/api_editor/server/data/packageData.kt rename to server/src/main/kotlin/com/larsreimann/api_editor/model/packageData.kt index a8940fb78..7112d351e 100644 --- a/server/src/main/kotlin/com/larsreimann/api_editor/server/data/packageData.kt +++ b/server/src/main/kotlin/com/larsreimann/api_editor/model/packageData.kt @@ -1,4 +1,4 @@ -package com.larsreimann.api_editor.server.data +package com.larsreimann.api_editor.model import kotlinx.serialization.Serializable import kotlinx.serialization.Transient diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/server/Application.kt b/server/src/main/kotlin/com/larsreimann/api_editor/server/Application.kt index d61623422..4accba540 100644 --- a/server/src/main/kotlin/com/larsreimann/api_editor/server/Application.kt +++ b/server/src/main/kotlin/com/larsreimann/api_editor/server/Application.kt @@ -1,13 +1,21 @@ package com.larsreimann.api_editor.server -import io.ktor.application.* -import io.ktor.features.* -import io.ktor.request.* -import io.ktor.server.engine.* -import io.ktor.server.netty.* +import de.unibonn.simpleml.SimpleMLStandaloneSetup +import io.ktor.application.Application +import io.ktor.application.install +import io.ktor.features.CallLogging +import io.ktor.features.Compression +import io.ktor.features.deflate +import io.ktor.features.gzip +import io.ktor.features.minimumSize +import io.ktor.request.path +import io.ktor.server.engine.embeddedServer +import io.ktor.server.netty.Netty import org.slf4j.event.Level fun main() { + SimpleMLStandaloneSetup.doSetup() + embeddedServer(Netty, port = 4280, host = "localhost") { configureHTTP() configureMonitoring() diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/server/Routing.kt b/server/src/main/kotlin/com/larsreimann/api_editor/server/Routing.kt index 62ac13744..163976e47 100644 --- a/server/src/main/kotlin/com/larsreimann/api_editor/server/Routing.kt +++ b/server/src/main/kotlin/com/larsreimann/api_editor/server/Routing.kt @@ -1,14 +1,14 @@ package com.larsreimann.api_editor.server -import com.larsreimann.api_editor.server.annotationProcessing.CleanupModulesProcessor -import com.larsreimann.api_editor.server.annotationProcessing.MoveAnnotationProcessor -import com.larsreimann.api_editor.server.annotationProcessing.OriginalDeclarationProcessor -import com.larsreimann.api_editor.server.annotationProcessing.PureAnnotationProcessor -import com.larsreimann.api_editor.server.annotationProcessing.RenameAnnotationProcessor -import com.larsreimann.api_editor.server.annotationProcessing.UnusedAnnotationProcessor -import com.larsreimann.api_editor.server.data.AnnotatedPythonPackage -import com.larsreimann.api_editor.server.file_handling.PackageFileBuilder -import com.larsreimann.api_editor.server.validation.AnnotationValidator +import com.larsreimann.api_editor.io.PackageFileBuilder +import com.larsreimann.api_editor.model.AnnotatedPythonPackage +import com.larsreimann.api_editor.transformation.CleanupModulesProcessor +import com.larsreimann.api_editor.transformation.MoveAnnotationProcessor +import com.larsreimann.api_editor.transformation.OriginalDeclarationProcessor +import com.larsreimann.api_editor.transformation.PureAnnotationProcessor +import com.larsreimann.api_editor.transformation.RenameAnnotationProcessor +import com.larsreimann.api_editor.transformation.UnusedAnnotationProcessor +import com.larsreimann.api_editor.validation.AnnotationValidator import io.ktor.application.Application import io.ktor.application.call import io.ktor.application.install diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/server/annotationProcessing/OriginalDeclarationProcessor.kt b/server/src/main/kotlin/com/larsreimann/api_editor/transformation/OriginalDeclarationProcessor.kt similarity index 62% rename from server/src/main/kotlin/com/larsreimann/api_editor/server/annotationProcessing/OriginalDeclarationProcessor.kt rename to server/src/main/kotlin/com/larsreimann/api_editor/transformation/OriginalDeclarationProcessor.kt index 2f5184bd9..da9f4afd0 100644 --- a/server/src/main/kotlin/com/larsreimann/api_editor/server/annotationProcessing/OriginalDeclarationProcessor.kt +++ b/server/src/main/kotlin/com/larsreimann/api_editor/transformation/OriginalDeclarationProcessor.kt @@ -1,9 +1,9 @@ -package com.larsreimann.api_editor.server.annotationProcessing +package com.larsreimann.api_editor.transformation -import com.larsreimann.api_editor.server.data.AbstractPackageDataVisitor -import com.larsreimann.api_editor.server.data.AnnotatedPythonClass -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction -import com.larsreimann.api_editor.server.data.AnnotatedPythonParameter +import com.larsreimann.api_editor.model.AbstractPackageDataVisitor +import com.larsreimann.api_editor.model.AnnotatedPythonClass +import com.larsreimann.api_editor.model.AnnotatedPythonFunction +import com.larsreimann.api_editor.model.AnnotatedPythonParameter object OriginalDeclarationProcessor : AbstractPackageDataVisitor() { diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/server/annotationProcessing/PureAnnotationProcessor.kt b/server/src/main/kotlin/com/larsreimann/api_editor/transformation/PureAnnotationProcessor.kt similarity index 66% rename from server/src/main/kotlin/com/larsreimann/api_editor/server/annotationProcessing/PureAnnotationProcessor.kt rename to server/src/main/kotlin/com/larsreimann/api_editor/transformation/PureAnnotationProcessor.kt index 6e294db08..6a0f96c1a 100644 --- a/server/src/main/kotlin/com/larsreimann/api_editor/server/annotationProcessing/PureAnnotationProcessor.kt +++ b/server/src/main/kotlin/com/larsreimann/api_editor/transformation/PureAnnotationProcessor.kt @@ -1,8 +1,8 @@ -package com.larsreimann.api_editor.server.annotationProcessing +package com.larsreimann.api_editor.transformation -import com.larsreimann.api_editor.server.data.AbstractPackageDataVisitor -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction -import com.larsreimann.api_editor.server.data.PureAnnotation +import com.larsreimann.api_editor.model.AbstractPackageDataVisitor +import com.larsreimann.api_editor.model.AnnotatedPythonFunction +import com.larsreimann.api_editor.model.PureAnnotation object PureAnnotationProcessor : AbstractPackageDataVisitor() { diff --git a/server/src/main/kotlin/com/larsreimann/api_editor/server/util/PackageDataFactories.kt b/server/src/main/kotlin/com/larsreimann/api_editor/util/PackageDataFactories.kt similarity index 88% rename from server/src/main/kotlin/com/larsreimann/api_editor/server/util/PackageDataFactories.kt rename to server/src/main/kotlin/com/larsreimann/api_editor/util/PackageDataFactories.kt index 9d08fe389..e4c5ecff5 100644 --- a/server/src/main/kotlin/com/larsreimann/api_editor/server/util/PackageDataFactories.kt +++ b/server/src/main/kotlin/com/larsreimann/api_editor/util/PackageDataFactories.kt @@ -1,15 +1,15 @@ -package com.larsreimann.api_editor.server.util +package com.larsreimann.api_editor.util -import com.larsreimann.api_editor.server.data.AnnotatedPythonClass -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction -import com.larsreimann.api_editor.server.data.AnnotatedPythonModule -import com.larsreimann.api_editor.server.data.AnnotatedPythonPackage -import com.larsreimann.api_editor.server.data.AnnotatedPythonParameter -import com.larsreimann.api_editor.server.data.AnnotatedPythonResult -import com.larsreimann.api_editor.server.data.EditorAnnotation -import com.larsreimann.api_editor.server.data.PythonFromImport -import com.larsreimann.api_editor.server.data.PythonImport -import com.larsreimann.api_editor.server.data.PythonParameterAssignment +import com.larsreimann.api_editor.model.AnnotatedPythonClass +import com.larsreimann.api_editor.model.AnnotatedPythonFunction +import com.larsreimann.api_editor.model.AnnotatedPythonModule +import com.larsreimann.api_editor.model.AnnotatedPythonPackage +import com.larsreimann.api_editor.model.AnnotatedPythonParameter +import com.larsreimann.api_editor.model.AnnotatedPythonResult +import com.larsreimann.api_editor.model.EditorAnnotation +import com.larsreimann.api_editor.model.PythonFromImport +import com.larsreimann.api_editor.model.PythonImport +import com.larsreimann.api_editor.model.PythonParameterAssignment @JvmOverloads fun createAnnotatedPythonPackage( diff --git a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/ClassAdapterContentBuilderTest.java b/server/src/test/java/com/larsreimann/api_editor/codegen/ClassAdapterContentBuilderTest.java similarity index 92% rename from server/src/test/java/com/larsreimann/api_editor/server/file_handling/ClassAdapterContentBuilderTest.java rename to server/src/test/java/com/larsreimann/api_editor/codegen/ClassAdapterContentBuilderTest.java index 8f2120c2a..712218b3a 100644 --- a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/ClassAdapterContentBuilderTest.java +++ b/server/src/test/java/com/larsreimann/api_editor/codegen/ClassAdapterContentBuilderTest.java @@ -1,8 +1,15 @@ -package com.larsreimann.api_editor.server.file_handling; - -import com.larsreimann.api_editor.server.annotationProcessing.OriginalDeclarationProcessor; -import com.larsreimann.api_editor.server.annotationProcessing.RenameAnnotationProcessor; -import com.larsreimann.api_editor.server.data.*; +package com.larsreimann.api_editor.codegen; + +import com.larsreimann.api_editor.codegen.ClassAdapterContentBuilder; +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonParameter; +import com.larsreimann.api_editor.model.AttributeAnnotation; +import com.larsreimann.api_editor.model.DefaultString; +import com.larsreimann.api_editor.model.PythonParameterAssignment; +import com.larsreimann.api_editor.model.RenameAnnotation; +import com.larsreimann.api_editor.transformation.OriginalDeclarationProcessor; +import com.larsreimann.api_editor.transformation.RenameAnnotationProcessor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/FunctionAdapterContentBuilderTest.java b/server/src/test/java/com/larsreimann/api_editor/codegen/FunctionAdapterContentBuilderTest.java similarity index 96% rename from server/src/test/java/com/larsreimann/api_editor/server/file_handling/FunctionAdapterContentBuilderTest.java rename to server/src/test/java/com/larsreimann/api_editor/codegen/FunctionAdapterContentBuilderTest.java index 4b67ddd28..23eb05db3 100644 --- a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/FunctionAdapterContentBuilderTest.java +++ b/server/src/test/java/com/larsreimann/api_editor/codegen/FunctionAdapterContentBuilderTest.java @@ -1,11 +1,12 @@ -package com.larsreimann.api_editor.server.file_handling; +package com.larsreimann.api_editor.codegen; -import com.larsreimann.api_editor.server.annotationProcessing.OriginalDeclarationProcessor; -import com.larsreimann.api_editor.server.annotationProcessing.RenameAnnotationProcessor; -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction; -import com.larsreimann.api_editor.server.data.AnnotatedPythonParameter; -import com.larsreimann.api_editor.server.data.PythonParameterAssignment; -import com.larsreimann.api_editor.server.data.RenameAnnotation; +import com.larsreimann.api_editor.codegen.FunctionAdapterContentBuilder; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonParameter; +import com.larsreimann.api_editor.model.PythonParameterAssignment; +import com.larsreimann.api_editor.model.RenameAnnotation; +import com.larsreimann.api_editor.transformation.OriginalDeclarationProcessor; +import com.larsreimann.api_editor.transformation.RenameAnnotationProcessor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/ModuleAdapterContentBuilderTest.java b/server/src/test/java/com/larsreimann/api_editor/codegen/ModuleAdapterContentBuilderTest.java similarity index 94% rename from server/src/test/java/com/larsreimann/api_editor/server/file_handling/ModuleAdapterContentBuilderTest.java rename to server/src/test/java/com/larsreimann/api_editor/codegen/ModuleAdapterContentBuilderTest.java index 5767ec963..8f337511d 100644 --- a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/ModuleAdapterContentBuilderTest.java +++ b/server/src/test/java/com/larsreimann/api_editor/codegen/ModuleAdapterContentBuilderTest.java @@ -1,7 +1,15 @@ -package com.larsreimann.api_editor.server.file_handling; +package com.larsreimann.api_editor.codegen; -import com.larsreimann.api_editor.server.annotationProcessing.OriginalDeclarationProcessor; -import com.larsreimann.api_editor.server.data.*; +import com.larsreimann.api_editor.codegen.ModuleAdapterContentBuilder; +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonParameter; +import com.larsreimann.api_editor.model.AnnotatedPythonResult; +import com.larsreimann.api_editor.model.PythonFromImport; +import com.larsreimann.api_editor.model.PythonImport; +import com.larsreimann.api_editor.model.PythonParameterAssignment; +import com.larsreimann.api_editor.transformation.OriginalDeclarationProcessor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/RenameAnnotationProcessorTest.java b/server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/RenameAnnotationProcessorTest.java deleted file mode 100644 index 4c7d05003..000000000 --- a/server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/RenameAnnotationProcessorTest.java +++ /dev/null @@ -1,326 +0,0 @@ -package com.larsreimann.api_editor.server.annotationProcessing; - -import com.larsreimann.api_editor.server.data.*; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; - -import static com.larsreimann.api_editor.server.util.PackageDataFactoriesKt.*; - -class RenameAnnotationProcessorTest { - @Test - void shouldRenameClass() { - // given - RenameAnnotationProcessor renameAnnotationProcessor = - new RenameAnnotationProcessor(); - - AnnotatedPythonClass testClass = - createAnnotatedPythonClass( - "testClass", - "testModule.testClass" - ); - testClass.getAnnotations().add( - new RenameAnnotation("renamedTestClass") - ); - - AnnotatedPythonModule testModule = - createAnnotatedPythonModule("testModule"); - testModule.getClasses().add(testClass); - - AnnotatedPythonPackage testPackage = - createAnnotatedPythonPackage("testPackage"); - testPackage.getModules().add(testModule); - - // when - testPackage.accept(renameAnnotationProcessor); - AnnotatedPythonPackage modifiedPackage = - renameAnnotationProcessor.getModifiedPackage(); - - // then - AnnotatedPythonClass renamedClass = modifiedPackage - .getModules().get(0) - .getClasses().get(0); - Assertions.assertEquals( - "renamedTestClass", - renamedClass.getName() - ); - Assertions.assertEquals( - "testModule.renamedTestClass", - renamedClass.getQualifiedName() - ); - } - - @Test - void shouldRenameGlobalFunction() { - // given - RenameAnnotationProcessor renameAnnotationProcessor = - new RenameAnnotationProcessor(); - - AnnotatedPythonFunction testFunction = - createAnnotatedPythonFunction( - "testFunction", - "testModule.testFunction" - ); - testFunction.getAnnotations().add( - new RenameAnnotation("renamedTestFunction") - ); - - AnnotatedPythonModule testModule = - createAnnotatedPythonModule("testModule"); - testModule.getFunctions().add(testFunction); - - AnnotatedPythonPackage testPackage = - createAnnotatedPythonPackage("testPackage"); - testPackage.getModules().add(testModule); - - // when - testPackage.accept(renameAnnotationProcessor); - AnnotatedPythonPackage modifiedPackage = - renameAnnotationProcessor.getModifiedPackage(); - - // then - AnnotatedPythonFunction renamedFunction = modifiedPackage - .getModules().get(0) - .getFunctions().get(0); - Assertions.assertEquals( - "renamedTestFunction", - renamedFunction.getName() - ); - Assertions.assertEquals( - "testModule.renamedTestFunction", - renamedFunction.getQualifiedName() - ); - } - - @Test - void shouldRenameClassMethod() { - // given - RenameAnnotationProcessor renameAnnotationProcessor = - new RenameAnnotationProcessor(); - - AnnotatedPythonFunction testFunction = - createAnnotatedPythonFunction( - "testFunction", - "testModule.testClass.testFunction" - ); - testFunction.getAnnotations().add( - new RenameAnnotation("renamedTestFunction") - ); - - ArrayList classMethods = new ArrayList<>(); - classMethods.add(testFunction); - AnnotatedPythonClass testClass = - createAnnotatedPythonClass( - "testClass", - "testModule.testClass", - new ArrayList<>(), - new ArrayList<>(), - classMethods - ); - - AnnotatedPythonModule testModule = - createAnnotatedPythonModule("testModule"); - testModule.getClasses().add(testClass); - - AnnotatedPythonPackage testPackage = - createAnnotatedPythonPackage("testPackage"); - testPackage.getModules().add(testModule); - - // when - testPackage.accept(renameAnnotationProcessor); - AnnotatedPythonPackage modifiedPackage = - renameAnnotationProcessor.getModifiedPackage(); - - // then - AnnotatedPythonFunction renamedFunction = modifiedPackage - .getModules().get(0) - .getClasses().get(0) - .getMethods().get(0); - Assertions.assertEquals( - "renamedTestFunction", - renamedFunction.getName() - ); - Assertions.assertEquals( - "testModule.testClass.renamedTestFunction", - renamedFunction.getQualifiedName() - ); - } - - @Test - void shouldRenameClassMethodAndClass() { - // given - RenameAnnotationProcessor renameAnnotationProcessor = - new RenameAnnotationProcessor(); - - AnnotatedPythonFunction testFunction = - createAnnotatedPythonFunction( - "testFunction", - "testModule.testClass.testFunction" - ); - testFunction.getAnnotations().add( - new RenameAnnotation("renamedTestFunction") - ); - - ArrayList classMethods = new ArrayList<>(); - classMethods.add(testFunction); - AnnotatedPythonClass testClass = - createAnnotatedPythonClass( - "testClass", - "testModule.testClass", - new ArrayList<>(), - new ArrayList<>(), - classMethods - ); - testClass.getAnnotations().add( - new RenameAnnotation("renamedTestClass") - ); - - AnnotatedPythonModule testModule = - createAnnotatedPythonModule("testModule"); - testModule.getClasses().add(testClass); - - AnnotatedPythonPackage testPackage = - createAnnotatedPythonPackage("testPackage"); - testPackage.getModules().add(testModule); - - // when - testPackage.accept(renameAnnotationProcessor); - AnnotatedPythonPackage modifiedPackage = - renameAnnotationProcessor.getModifiedPackage(); - - // then - AnnotatedPythonClass renamedClass = modifiedPackage - .getModules().get(0) - .getClasses().get(0); - AnnotatedPythonFunction renamedFunction = renamedClass.getMethods().get(0); - Assertions.assertEquals( - "testModule.renamedTestClass.renamedTestFunction", - renamedFunction.getQualifiedName() - ); - Assertions.assertEquals( - "testModule.renamedTestClass", - renamedClass.getQualifiedName() - ); - } - - @Test - void shouldRenameClassMethodParameterAndClassMethodAndClass() { - // given - RenameAnnotationProcessor renameAnnotationProcessor = - new RenameAnnotationProcessor(); - - AnnotatedPythonParameter pythonParameter = - createAnnotatedPythonParameter("testParameter"); - pythonParameter.getAnnotations().add( - new RenameAnnotation("renamedTestParameter") - ); - - ArrayList pythonParameters = - new ArrayList<>(); - pythonParameters.add(pythonParameter); - - AnnotatedPythonFunction testFunction = - createAnnotatedPythonFunction( - "testFunction", - "testModule.testClass.testFunction", - new ArrayList<>(), - pythonParameters - ); - testFunction.getAnnotations().add( - new RenameAnnotation("renamedTestFunction") - ); - - ArrayList classMethods = new ArrayList<>(); - classMethods.add(testFunction); - AnnotatedPythonClass testClass = - createAnnotatedPythonClass( - "testClass", - "testModule.testClass", - new ArrayList<>(), - new ArrayList<>(), - classMethods - ); - testClass.getAnnotations().add( - new RenameAnnotation("renamedTestClass") - ); - - AnnotatedPythonModule testModule = - createAnnotatedPythonModule("testModule"); - testModule.getClasses().add(testClass); - - AnnotatedPythonPackage testPackage = - createAnnotatedPythonPackage("testPackage"); - testPackage.getModules().add(testModule); - - // when - testPackage.accept(renameAnnotationProcessor); - AnnotatedPythonPackage modifiedPackage = - renameAnnotationProcessor.getModifiedPackage(); - - // then - AnnotatedPythonParameter renamedParameter = modifiedPackage - .getModules().get(0) - .getClasses().get(0). - getMethods().get(0) - .getParameters().get(0); - Assertions.assertEquals( - "renamedTestParameter", - renamedParameter.getName() - ); - Assertions.assertEquals( - "testModule.renamedTestClass.renamedTestFunction.renamedTestParameter", - renamedParameter.getQualifiedName() - ); - } - - @Test - void shouldRenameGlobalFunctionParameterAndGlobalFunction() { - // given - RenameAnnotationProcessor renameAnnotationProcessor = - new RenameAnnotationProcessor(); - - AnnotatedPythonParameter pythonParameter = - createAnnotatedPythonParameter("testParameter"); - pythonParameter.getAnnotations().add( - new RenameAnnotation("renamedTestParameter") - ); - - AnnotatedPythonFunction testFunction = - createAnnotatedPythonFunction( - "testFunction", - "testModule.testFunction" - ); - testFunction.getParameters().add(pythonParameter); - testFunction.getAnnotations().add( - new RenameAnnotation("renamedTestFunction") - ); - - AnnotatedPythonModule testModule = - createAnnotatedPythonModule("testModule"); - testModule.getFunctions().add(testFunction); - - AnnotatedPythonPackage testPackage = - createAnnotatedPythonPackage("testPackage"); - testPackage.getModules().add(testModule); - - // when - testPackage.accept(renameAnnotationProcessor); - AnnotatedPythonPackage modifiedPackage = - renameAnnotationProcessor.getModifiedPackage(); - - // then - AnnotatedPythonParameter renamedParameter = modifiedPackage - .getModules().get(0) - .getFunctions().get(0) - .getParameters().get(0); - Assertions.assertEquals( - "renamedTestParameter", - renamedParameter.getName() - ); - Assertions.assertEquals( - "testModule.renamedTestFunction.renamedTestParameter", - renamedParameter.getQualifiedName() - ); - } -} diff --git a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/ClassStubContentBuilderTest.java b/server/src/test/java/com/larsreimann/api_editor/server/file_handling/ClassStubContentBuilderTest.java deleted file mode 100644 index 035026a9c..000000000 --- a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/ClassStubContentBuilderTest.java +++ /dev/null @@ -1,152 +0,0 @@ -package com.larsreimann.api_editor.server.file_handling; - -import com.larsreimann.api_editor.server.data.*; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.Collections; -import java.util.List; - -class ClassStubContentBuilderTest { - @Test - void buildClassReturnsFormattedClassWithNoConstructorAndFunctions() { - // given - AnnotatedPythonClass testClass = new AnnotatedPythonClass( - "test-class", - "test-module.test-class", - List.of("test-decorator"), - List.of("test-superclass"), - Collections.emptyList(), - "Lorem ipsum", - "Lorem ipsum", - Collections.emptyList() - ); - - // when - ClassStubContentBuilder classStubContentBuilder = - new ClassStubContentBuilder(testClass); - String formattedClass = classStubContentBuilder.buildClass(); - - // then - String expectedFormattedClass = "open class test-class() {}"; - Assertions.assertEquals(expectedFormattedClass, formattedClass); - } - - @Test - void buildClassReturnsFormattedClassWithOneFunctionAndNoConstructor() { - // given - AnnotatedPythonClass testClass = new AnnotatedPythonClass( - "test-class", - "test-module.test-class", - List.of("test-decorator"), - List.of("test-superclass"), - List.of(new AnnotatedPythonFunction( - "test-class-function", - "test-module.test-class.test-class-function", - List.of("decorators"), - List.of(new AnnotatedPythonParameter( - "only-param", - "test-module.test-class.test-class-function.only-param", - "'defaultValue'", - PythonParameterAssignment.POSITION_OR_NAME, - true, - "str", - "description", - List.of(new AttributeAnnotation( - new DefaultString("test") - )) - )), - Collections.emptyList(), - true, - "description", - "fullDocstring", - Collections.emptyList() - )), - "Lorem ipsum", - "Lorem ipsum", - Collections.emptyList() - ); - - // when - ClassStubContentBuilder classStubContentBuilder = - new ClassStubContentBuilder(testClass); - String formattedClass = classStubContentBuilder.buildClass(); - - // then - String expectedFormattedClass = """ - open class test-class() { - fun test-class-function(only-param: Any? or "defaultValue") - }"""; - Assertions.assertEquals(expectedFormattedClass, formattedClass); - } - - @Test - void buildClassReturnsFormattedClassWithConstructorAndOneFunction() { - // given - AnnotatedPythonClass testClass = new AnnotatedPythonClass( - "test-class", - "test-module.test-class", - List.of("test-decorator"), - List.of("test-superclass"), - List.of( - new AnnotatedPythonFunction( - "test-class-function1", - "test-module.test-class.test-class-function1", - List.of("decorators"), - List.of(new AnnotatedPythonParameter( - "only-param", - "test-module.test-class.test-class-function.only-param", - null, - PythonParameterAssignment.POSITION_OR_NAME, - true, - "typeInDocs", - "description", - Collections.emptyList() - )), - Collections.emptyList(), - true, - "description", - "fullDocstring", - Collections.emptyList() - ), - new AnnotatedPythonFunction( - "__init__", - "test-module.test-class.__init__", - List.of("decorators"), - List.of(new AnnotatedPythonParameter( - "only-param", - "test-module.test-class.__init__.only-param", - null, - PythonParameterAssignment.POSITION_OR_NAME, - true, - "typeInDocs", - "description", - Collections.emptyList() - )), - Collections.emptyList(), - true, - "description", - "fullDocstring", - Collections.emptyList() - ) - ), - "Lorem ipsum", - "Lorem ipsum", - Collections.emptyList() - ); - - // when - ClassStubContentBuilder classStubContentBuilder = - new ClassStubContentBuilder(testClass); - String formattedClass = classStubContentBuilder.buildClass(); - - // then - String expectedFormattedClass = """ - open class test-class(only-param: Any?) { - attr only-param: Any? - - fun test-class-function1(only-param: Any?) - }"""; - Assertions.assertEquals(formattedClass, expectedFormattedClass); - } -} diff --git a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/FunctionStubContentBuilderTest.java b/server/src/test/java/com/larsreimann/api_editor/server/file_handling/FunctionStubContentBuilderTest.java deleted file mode 100644 index 5ae00dc6a..000000000 --- a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/FunctionStubContentBuilderTest.java +++ /dev/null @@ -1,325 +0,0 @@ -package com.larsreimann.api_editor.server.file_handling; - -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction; -import com.larsreimann.api_editor.server.data.AnnotatedPythonParameter; -import com.larsreimann.api_editor.server.data.AnnotatedPythonResult; -import com.larsreimann.api_editor.server.data.PythonParameterAssignment; -import com.larsreimann.api_editor.server.util.PackageDataFactoriesKt; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.Collections; -import java.util.List; - -class FunctionStubContentBuilderTest { - @Test - void buildFunctionReturnsFormattedFunctionWithNoParameters() { - // given - AnnotatedPythonFunction testFunction = new AnnotatedPythonFunction( - "test-function", - "test-module.test-function", - List.of("test-decorator"), - Collections.emptyList(), - Collections.emptyList(), - true, - "Lorem ipsum", - "fullDocstring", - Collections.emptyList() - ); - - // when - FunctionStubContentBuilder functionStubContentBuilder = - new FunctionStubContentBuilder(testFunction); - String formattedFunction = functionStubContentBuilder.buildFunction(); - - // then - String expectedFormattedFunction = """ - fun test-function()"""; - Assertions.assertEquals(expectedFormattedFunction, formattedFunction); - } - - @Test - void buildFunctionReturnsFormattedFunctionWithPositionOnlyParameter() { - // given - AnnotatedPythonFunction testFunction = new AnnotatedPythonFunction( - "test-function", - "test-module.test-function", - List.of("test-decorator"), - List.of( - new AnnotatedPythonParameter( - "only-param", - "test-module.test-class.test-class-function.only-param", - "13", - PythonParameterAssignment.POSITION_ONLY, - true, - "int", - "description", - Collections.emptyList() - ) - ), - Collections.emptyList(), - true, - "Lorem ipsum", - "fullDocstring", - Collections.emptyList() - ); - - // when - FunctionStubContentBuilder functionStubContentBuilder = - new FunctionStubContentBuilder(testFunction); - String formattedFunction = functionStubContentBuilder.buildFunction(); - - // then - String expectedFormattedFunction = """ - fun test-function(only-param: Any? or 13)"""; - Assertions.assertEquals(expectedFormattedFunction, formattedFunction); - } - - @Test - void buildFunctionReturnsFormattedFunctionWithPositionOrNameParameter() { - // given - AnnotatedPythonFunction testFunction = new AnnotatedPythonFunction( - "test-function", - "test-module.test-function", - List.of("test-decorator"), - List.of( - new AnnotatedPythonParameter( - "only-param", - "test-module.test-class.test-class-function.only-param", - "'Test'", - PythonParameterAssignment.POSITION_OR_NAME, - true, - "string", - "description", - Collections.emptyList() - ) - ), - Collections.emptyList(), - true, - "Lorem ipsum", - "fullDocstring", - Collections.emptyList() - ); - - // when - FunctionStubContentBuilder functionStubContentBuilder = - new FunctionStubContentBuilder(testFunction); - String formattedFunction = functionStubContentBuilder.buildFunction(); - - // then - String expectedFormattedFunction = """ - fun test-function(only-param: Any? or "Test")"""; - Assertions.assertEquals(expectedFormattedFunction, formattedFunction); - } - - @Test - void buildFunctionReturnsFormattedFunctionWithPositionAndPositionOrNameAndNameOnlyParameter() { - // given - AnnotatedPythonFunction testFunction = new AnnotatedPythonFunction( - "test-function", - "test-module.test-function", - List.of("test-decorator"), - List.of( - new AnnotatedPythonParameter( - "first-param", - "test-module.test-class.test-class-function.first-param", - null, - PythonParameterAssignment.POSITION_ONLY, - true, - "typeInDocs", - "description", - Collections.emptyList() - ), - new AnnotatedPythonParameter( - "second-param", - "test-module.test-class.test-class-function.second-param", - null, - PythonParameterAssignment.POSITION_OR_NAME, - true, - "typeInDocs", - "description", - Collections.emptyList() - ), - new AnnotatedPythonParameter( - "third-param", - "test-module.test-class.test-class-function.third-param", - null, - PythonParameterAssignment.NAME_ONLY, - true, - "typeInDocs", - "description", - Collections.emptyList() - ) - ), - Collections.emptyList(), - true, - "Lorem ipsum", - "fullDocstring", - Collections.emptyList() - ); - - // when - FunctionStubContentBuilder functionStubContentBuilder = - new FunctionStubContentBuilder(testFunction); - String formattedFunction = functionStubContentBuilder.buildFunction(); - - // then - String expectedFormattedFunction = """ - fun test-function(first-param: Any?, second-param: Any?, third-param: Any?)"""; - Assertions.assertEquals(expectedFormattedFunction, formattedFunction); - } - - @Test - void buildFunctionReturnsFormattedFunctionWithOneResult() { - // given - AnnotatedPythonFunction testFunction = new AnnotatedPythonFunction( - "test-function", - "test-module.test-function", - List.of("test-decorator"), - List.of( - new AnnotatedPythonParameter( - "only-param", - "test-module.test-class.test-class-function.only-param", - "1.31e+1", - PythonParameterAssignment.POSITION_ONLY, - true, - "float", - "description", - Collections.emptyList() - ) - ), - List.of( - new AnnotatedPythonResult( - "firstResult", - "float", - "float", - "description", - Collections.emptyList() - ) - ), - true, - "Lorem ipsum", - "fullDocstring", - Collections.emptyList() - ); - - // when - FunctionStubContentBuilder functionStubContentBuilder = - new FunctionStubContentBuilder(testFunction); - String formattedFunction = functionStubContentBuilder.buildFunction(); - - // then - String expectedFormattedFunction = """ - fun test-function(only-param: Any? or 13.1) -> firstResult: float"""; - Assertions.assertEquals(expectedFormattedFunction, formattedFunction); - } - - @Test - void buildFunctionReturnsFormattedFunctionWithMultipleResults() { - // given - AnnotatedPythonFunction testFunction = new AnnotatedPythonFunction( - "test-function", - "test-module.test-function", - List.of("test-decorator"), - List.of( - new AnnotatedPythonParameter( - "only-param", - "test-module.test-class.test-class-function.only-param", - "True", - PythonParameterAssignment.POSITION_ONLY, - true, - "bool", - "description", - Collections.emptyList() - ) - ), - List.of( - new AnnotatedPythonResult( - "firstResult", - "float", - "float", - "description", - Collections.emptyList() - ), - new AnnotatedPythonResult( - "secondResult", - "float", - "float", - "description", - Collections.emptyList() - ) - ), - true, - "Lorem ipsum", - "fullDocstring", - Collections.emptyList() - ); - - // when - FunctionStubContentBuilder functionStubContentBuilder = - new FunctionStubContentBuilder(testFunction); - String formattedFunction = functionStubContentBuilder.buildFunction(); - - // then - String expectedFormattedFunction = """ - fun test-function(only-param: Any? or true) -> [firstResult: float, secondResult: float]"""; - Assertions.assertEquals(expectedFormattedFunction, formattedFunction); - } - - @Test - void buildFunctionReturnsFormattedFunctionWithInvalidDefaultValue() { - // given - AnnotatedPythonFunction testFunction = new AnnotatedPythonFunction( - "test-function", - "test-module.test-function", - List.of("test-decorator"), - List.of( - new AnnotatedPythonParameter( - "only-param", - "test-module.test-class.test-class-function.only-param", - "'13'x", - PythonParameterAssignment.POSITION_ONLY, - true, - "string", - "description", - Collections.emptyList() - ) - ), - Collections.emptyList(), - true, - "Lorem ipsum", - "fullDocstring", - Collections.emptyList() - ); - - // when - FunctionStubContentBuilder functionStubContentBuilder = - new FunctionStubContentBuilder(testFunction); - String formattedFunction = functionStubContentBuilder.buildFunction(); - - // then - String expectedFormattedFunction = """ - fun test-function(only-param: Any? or "###invalid###'13'x###")"""; - Assertions.assertEquals(expectedFormattedFunction, formattedFunction); - } - - @Test - void shouldMarkPureFunctionsWithAnnotation() { - // given - AnnotatedPythonFunction testFunction = PackageDataFactoriesKt.createAnnotatedPythonFunction( - "testFunction" - ); - testFunction.setPure(true); - - // when - FunctionStubContentBuilder functionStubContentBuilder = - new FunctionStubContentBuilder(testFunction); - String formattedFunction = functionStubContentBuilder.buildFunction(); - - // then - String expectedFormattedFunction = """ - @Pure - fun testFunction()"""; - Assertions.assertEquals(expectedFormattedFunction, formattedFunction); - } -} diff --git a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/ModuleStubContentBuilderTest.java b/server/src/test/java/com/larsreimann/api_editor/server/file_handling/ModuleStubContentBuilderTest.java deleted file mode 100644 index d234dd5f8..000000000 --- a/server/src/test/java/com/larsreimann/api_editor/server/file_handling/ModuleStubContentBuilderTest.java +++ /dev/null @@ -1,390 +0,0 @@ -package com.larsreimann.api_editor.server.file_handling; - -import com.larsreimann.api_editor.server.data.*; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.Collections; -import java.util.List; - -class ModuleStubContentBuilderTest { - @Test - void buildModuleContentReturnsFormattedModuleContent() { - // given - AnnotatedPythonClass testClass = new AnnotatedPythonClass( - "test-class", - "test-module.test-class", - List.of("test-decorator"), - List.of("test-superclass"), - List.of( - new AnnotatedPythonFunction( - "test-class-function", - "test-module.test-class.test-class-function", - List.of("decorators"), - List.of( - new AnnotatedPythonParameter( - "only-param", - "test-module.test-class.test-class-function.only-param", - "'defaultValue'", - PythonParameterAssignment.POSITION_OR_NAME, - true, - "typeInDocs", - "description", - Collections.emptyList() - )), - Collections.emptyList(), - true, - "description", - "fullDocstring", - Collections.emptyList() - ), - new AnnotatedPythonFunction( - "__init__", - "test-module.test-class.__init__", - List.of("decorators"), - List.of(new AnnotatedPythonParameter( - "only-param", - "test-module.test-class.__init__.only-param", - "'defaultValue'", - PythonParameterAssignment.POSITION_OR_NAME, - true, - "typeInDocs", - "description", - Collections.emptyList() - )), - Collections.emptyList(), - true, - "description", - "fullDocstring", - Collections.emptyList() - )), - "Lorem ipsum", - "Lorem ipsum", - Collections.emptyList() - ); - - AnnotatedPythonModule testModule = new AnnotatedPythonModule( - "test-module", - Collections.emptyList(), - Collections.emptyList(), - List.of( - testClass - ), - List.of( - new AnnotatedPythonFunction( - "function_module", - "test-module.function_module", - List.of("test-decorator"), - List.of( - new AnnotatedPythonParameter( - "param1", - "test-module.function_module.param1", - null, - PythonParameterAssignment.NAME_ONLY, - true, - "str", - "Lorem ipsum", - Collections.emptyList() - ), - new AnnotatedPythonParameter( - "param2", - "test-module.function_module.param2", - null, - PythonParameterAssignment.NAME_ONLY, - true, - "str", - "Lorem ipsum", - Collections.emptyList() - ), - new AnnotatedPythonParameter( - "param3", - "test-module.function_module.param3", - null, - PythonParameterAssignment.NAME_ONLY, - true, - "str", - "Lorem ipsum", - Collections.emptyList() - ) - ), - List.of( - new AnnotatedPythonResult( - "test-result", - "str", - "str", - "Lorem ipsum", - Collections.emptyList() - ) - ), - true, - "Lorem ipsum", - "Lorem ipsum", - Collections.emptyList() - ), - new AnnotatedPythonFunction( - "test-function", - "test-module.test-function", - List.of("test-decorator"), - List.of( - new AnnotatedPythonParameter( - "test-parameter", - "test-module.test-function.test-parameter", - "42", - PythonParameterAssignment.NAME_ONLY, - true, - "int", - "Lorem ipsum", - Collections.emptyList() - ) - ), - List.of( - new AnnotatedPythonResult( - "test-result", - "str", - "str", - "Lorem ipsum", - Collections.emptyList() - ) - ), - true, - "Lorem ipsum", - "Lorem ipsum", - Collections.emptyList() - ) - ), - Collections.emptyList() - ); - - // when - ModuleStubContentBuilder moduleStubContentBuilder = - new ModuleStubContentBuilder(testModule); - String moduleContent = moduleStubContentBuilder.buildModuleContent(); - - //then - String expectedModuleContent = """ - package simpleml.test-module - - open class test-class(only-param: Any? or "defaultValue") { - attr only-param: Any? - - fun test-class-function(only-param: Any? or "defaultValue") - } - - fun function_module(param1: Any?, param2: Any?, param3: Any?) -> test-result: str - - fun test-function(test-parameter: Any? or 42) -> test-result: str - """; - - Assertions.assertEquals(expectedModuleContent, moduleContent); - } - - @Test - void buildModuleContentWithNoClassesReturnsFormattedModuleContent() { - // given - AnnotatedPythonModule testModule = new AnnotatedPythonModule( - "test-module", - Collections.emptyList(), - Collections.emptyList(), - Collections.emptyList(), - List.of( - new AnnotatedPythonFunction( - "function_module", - "test-module.function_module", - List.of("test-decorator"), - List.of( - new AnnotatedPythonParameter( - "param1", - "test-module.function_module.param1", - null, - PythonParameterAssignment.NAME_ONLY, - true, - "str", - "Lorem ipsum", - Collections.emptyList() - ), - new AnnotatedPythonParameter( - "param2", - "test-module.function_module.param2", - null, - PythonParameterAssignment.NAME_ONLY, - true, - "str", - "Lorem ipsum", - Collections.emptyList() - ), - new AnnotatedPythonParameter( - "param3", - "test-module.function_module.param3", - null, - PythonParameterAssignment.NAME_ONLY, - true, - "str", - "Lorem ipsum", - Collections.emptyList() - ) - ), - List.of( - new AnnotatedPythonResult( - "test-result", - "str", - "str", - "Lorem ipsum", - Collections.emptyList() - ) - ), - true, - "Lorem ipsum", - "Lorem ipsum", - Collections.emptyList() - ), - new AnnotatedPythonFunction( - "test-function", - "test-module.test-function", - List.of("test-decorator"), - List.of( - new AnnotatedPythonParameter( - "test-parameter", - "test-module.test-function.test-parameter", - "42", - PythonParameterAssignment.NAME_ONLY, - true, - "int", - "Lorem ipsum", - Collections.emptyList() - ) - ), - List.of( - new AnnotatedPythonResult( - "test-result", - "str", - "str", - "Lorem ipsum", - Collections.emptyList() - ) - ), - true, - "Lorem ipsum", - "Lorem ipsum", - Collections.emptyList() - ) - ), - Collections.emptyList() - ); - - // when - ModuleStubContentBuilder moduleStubContentBuilder = - new ModuleStubContentBuilder(testModule); - String moduleContent = moduleStubContentBuilder.buildModuleContent(); - - //then - String expectedModuleContent = """ - package simpleml.test-module - - fun function_module(param1: Any?, param2: Any?, param3: Any?) -> test-result: str - - fun test-function(test-parameter: Any? or 42) -> test-result: str - """; - - Assertions.assertEquals(expectedModuleContent, moduleContent); - } - - @Test - void buildModuleContentWithOnlyConstructorReturnsFormattedModuleContent() { - // given - AnnotatedPythonClass testClass = new AnnotatedPythonClass( - "test-class", - "test-module.test-class", - List.of("test-decorator"), - List.of("test-superclass"), - List.of( - new AnnotatedPythonFunction( - "__init__", - "test-module.test-class.__init__", - List.of("decorators"), - List.of(new AnnotatedPythonParameter( - "only-param", - "test-module.test-class.__init__.only-param", - "'defaultValue'", - PythonParameterAssignment.POSITION_OR_NAME, - true, - "typeInDocs", - "description", - Collections.emptyList() - )), - Collections.emptyList(), - true, - "description", - "fullDocstring", - Collections.emptyList() - ) - ), - "Lorem ipsum", - "Lorem ipsum", - Collections.emptyList() - ); - - AnnotatedPythonModule testModule = new AnnotatedPythonModule( - "test-module", - List.of( - new PythonImport( - "test-import1", - "test-alias" - ) - ), - List.of( - new PythonFromImport( - "test-from-import1", - "test-declaration1", - null - ) - ), - List.of( - testClass - ), - Collections.emptyList(), - Collections.emptyList() - ); - - // when - ModuleStubContentBuilder moduleStubContentBuilder = - new ModuleStubContentBuilder(testModule); - String moduleContent = moduleStubContentBuilder.buildModuleContent(); - - //then - String expectedModuleContent = """ - package simpleml.test-module - - open class test-class(only-param: Any? or "defaultValue") { - attr only-param: Any? - } - """; - - Assertions.assertEquals(expectedModuleContent, moduleContent); - } - - @Test - void buildModuleContentWithNoFunctionsAndClassesReturnsFormattedModuleContent() { - // given - AnnotatedPythonModule testModule = new AnnotatedPythonModule( - "test-module", - Collections.emptyList(), - Collections.emptyList(), - Collections.emptyList(), - Collections.emptyList(), - Collections.emptyList() - ); - - // when - ModuleStubContentBuilder moduleStubContentBuilder = - new ModuleStubContentBuilder(testModule); - String moduleContent = moduleStubContentBuilder.buildModuleContent(); - - //then - String expectedModuleContent = """ - package simpleml.test-module - """; - - Assertions.assertEquals(expectedModuleContent, moduleContent); - } -} - diff --git a/server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/CleanupModulesProcessorTest.java b/server/src/test/java/com/larsreimann/api_editor/transformation/CleanupModulesProcessorTest.java similarity index 78% rename from server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/CleanupModulesProcessorTest.java rename to server/src/test/java/com/larsreimann/api_editor/transformation/CleanupModulesProcessorTest.java index 0ad91d390..bafe56c9f 100644 --- a/server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/CleanupModulesProcessorTest.java +++ b/server/src/test/java/com/larsreimann/api_editor/transformation/CleanupModulesProcessorTest.java @@ -1,13 +1,16 @@ -package com.larsreimann.api_editor.server.annotationProcessing; +package com.larsreimann.api_editor.transformation; -import com.larsreimann.api_editor.server.data.AnnotatedPythonClass; -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction; -import com.larsreimann.api_editor.server.data.AnnotatedPythonModule; -import com.larsreimann.api_editor.server.data.AnnotatedPythonPackage; +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonPackage; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static com.larsreimann.api_editor.server.util.PackageDataFactoriesKt.*; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonClass; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonFunction; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonModule; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonPackage; class CleanupModulesProcessorTest { @Test diff --git a/server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/MoveAnnotationProcessorTest.java b/server/src/test/java/com/larsreimann/api_editor/transformation/MoveAnnotationProcessorTest.java similarity index 91% rename from server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/MoveAnnotationProcessorTest.java rename to server/src/test/java/com/larsreimann/api_editor/transformation/MoveAnnotationProcessorTest.java index a93e03a9c..0c6e9923a 100644 --- a/server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/MoveAnnotationProcessorTest.java +++ b/server/src/test/java/com/larsreimann/api_editor/transformation/MoveAnnotationProcessorTest.java @@ -1,10 +1,19 @@ -package com.larsreimann.api_editor.server.annotationProcessing; - -import com.larsreimann.api_editor.server.data.*; +package com.larsreimann.api_editor.transformation; + +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonPackage; +import com.larsreimann.api_editor.model.AnnotatedPythonParameter; +import com.larsreimann.api_editor.model.MoveAnnotation; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static com.larsreimann.api_editor.server.util.PackageDataFactoriesKt.*; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonClass; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonFunction; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonModule; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonPackage; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonParameter; class MoveAnnotationProcessorTest { @Test diff --git a/server/src/test/java/com/larsreimann/api_editor/transformation/RenameAnnotationProcessorTest.java b/server/src/test/java/com/larsreimann/api_editor/transformation/RenameAnnotationProcessorTest.java new file mode 100644 index 000000000..64133e8c0 --- /dev/null +++ b/server/src/test/java/com/larsreimann/api_editor/transformation/RenameAnnotationProcessorTest.java @@ -0,0 +1,335 @@ +package com.larsreimann.api_editor.transformation; + +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonPackage; +import com.larsreimann.api_editor.model.AnnotatedPythonParameter; +import com.larsreimann.api_editor.model.RenameAnnotation; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonClass; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonFunction; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonModule; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonPackage; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonParameter; + +class RenameAnnotationProcessorTest { + @Test + void shouldRenameClass() { + // given + RenameAnnotationProcessor renameAnnotationProcessor = + new RenameAnnotationProcessor(); + + AnnotatedPythonClass testClass = + createAnnotatedPythonClass( + "testClass", + "testModule.testClass" + ); + testClass.getAnnotations().add( + new RenameAnnotation("renamedTestClass") + ); + + AnnotatedPythonModule testModule = + createAnnotatedPythonModule("testModule"); + testModule.getClasses().add(testClass); + + AnnotatedPythonPackage testPackage = + createAnnotatedPythonPackage("testPackage"); + testPackage.getModules().add(testModule); + + // when + testPackage.accept(renameAnnotationProcessor); + AnnotatedPythonPackage modifiedPackage = + renameAnnotationProcessor.getModifiedPackage(); + + // then + AnnotatedPythonClass renamedClass = modifiedPackage + .getModules().get(0) + .getClasses().get(0); + Assertions.assertEquals( + "renamedTestClass", + renamedClass.getName() + ); + Assertions.assertEquals( + "testModule.renamedTestClass", + renamedClass.getQualifiedName() + ); + } + + @Test + void shouldRenameGlobalFunction() { + // given + RenameAnnotationProcessor renameAnnotationProcessor = + new RenameAnnotationProcessor(); + + AnnotatedPythonFunction testFunction = + createAnnotatedPythonFunction( + "testFunction", + "testModule.testFunction" + ); + testFunction.getAnnotations().add( + new RenameAnnotation("renamedTestFunction") + ); + + AnnotatedPythonModule testModule = + createAnnotatedPythonModule("testModule"); + testModule.getFunctions().add(testFunction); + + AnnotatedPythonPackage testPackage = + createAnnotatedPythonPackage("testPackage"); + testPackage.getModules().add(testModule); + + // when + testPackage.accept(renameAnnotationProcessor); + AnnotatedPythonPackage modifiedPackage = + renameAnnotationProcessor.getModifiedPackage(); + + // then + AnnotatedPythonFunction renamedFunction = modifiedPackage + .getModules().get(0) + .getFunctions().get(0); + Assertions.assertEquals( + "renamedTestFunction", + renamedFunction.getName() + ); + Assertions.assertEquals( + "testModule.renamedTestFunction", + renamedFunction.getQualifiedName() + ); + } + + @Test + void shouldRenameClassMethod() { + // given + RenameAnnotationProcessor renameAnnotationProcessor = + new RenameAnnotationProcessor(); + + AnnotatedPythonFunction testFunction = + createAnnotatedPythonFunction( + "testFunction", + "testModule.testClass.testFunction" + ); + testFunction.getAnnotations().add( + new RenameAnnotation("renamedTestFunction") + ); + + ArrayList classMethods = new ArrayList<>(); + classMethods.add(testFunction); + AnnotatedPythonClass testClass = + createAnnotatedPythonClass( + "testClass", + "testPackage.testModule.testClass", + new ArrayList<>(), + new ArrayList<>(), + classMethods + ); + + AnnotatedPythonModule testModule = + createAnnotatedPythonModule("testModule"); + testModule.getClasses().add(testClass); + + AnnotatedPythonPackage testPackage = + createAnnotatedPythonPackage("testPackage"); + testPackage.getModules().add(testModule); + + // when + testPackage.accept(renameAnnotationProcessor); + AnnotatedPythonPackage modifiedPackage = + renameAnnotationProcessor.getModifiedPackage(); + + // then + AnnotatedPythonFunction renamedFunction = modifiedPackage + .getModules().get(0) + .getClasses().get(0) + .getMethods().get(0); + Assertions.assertEquals( + "renamedTestFunction", + renamedFunction.getName() + ); + Assertions.assertEquals( + "testModule.testClass.renamedTestFunction", + renamedFunction.getQualifiedName() + ); + } + + @Test + void shouldRenameClassMethodAndClass() { + // given + RenameAnnotationProcessor renameAnnotationProcessor = + new RenameAnnotationProcessor(); + + AnnotatedPythonFunction testFunction = + createAnnotatedPythonFunction( + "testFunction", + "testModule.testClass.testFunction" + ); + testFunction.getAnnotations().add( + new RenameAnnotation("renamedTestFunction") + ); + + ArrayList classMethods = new ArrayList<>(); + classMethods.add(testFunction); + AnnotatedPythonClass testClass = + createAnnotatedPythonClass( + "testClass", + "testModule.testClass", + new ArrayList<>(), + new ArrayList<>(), + classMethods + ); + testClass.getAnnotations().add( + new RenameAnnotation("renamedTestClass") + ); + + AnnotatedPythonModule testModule = + createAnnotatedPythonModule("testModule"); + testModule.getClasses().add(testClass); + + AnnotatedPythonPackage testPackage = + createAnnotatedPythonPackage("testPackage"); + testPackage.getModules().add(testModule); + + // when + testPackage.accept(renameAnnotationProcessor); + AnnotatedPythonPackage modifiedPackage = + renameAnnotationProcessor.getModifiedPackage(); + + // then + AnnotatedPythonClass renamedClass = modifiedPackage + .getModules().get(0) + .getClasses().get(0); + AnnotatedPythonFunction renamedFunction = renamedClass.getMethods().get(0); + Assertions.assertEquals( + "testModule.renamedTestClass.renamedTestFunction", + renamedFunction.getQualifiedName() + ); + Assertions.assertEquals( + "testModule.renamedTestClass", + renamedClass.getQualifiedName() + ); + } + + @Test + void shouldRenameClassMethodParameterAndClassMethodAndClass() { + // given + RenameAnnotationProcessor renameAnnotationProcessor = + new RenameAnnotationProcessor(); + + AnnotatedPythonParameter pythonParameter = + createAnnotatedPythonParameter("testParameter"); + pythonParameter.getAnnotations().add( + new RenameAnnotation("renamedTestParameter") + ); + + ArrayList pythonParameters = + new ArrayList<>(); + pythonParameters.add(pythonParameter); + + AnnotatedPythonFunction testFunction = + createAnnotatedPythonFunction( + "testFunction", + "testPackage.testModule.testClass.testFunction", + new ArrayList<>(), + pythonParameters + ); + testFunction.getAnnotations().add( + new RenameAnnotation("renamedTestFunction") + ); + + ArrayList classMethods = new ArrayList<>(); + classMethods.add(testFunction); + AnnotatedPythonClass testClass = + createAnnotatedPythonClass( + "testClass", + "testPackage.testModule.testClass", + new ArrayList<>(), + new ArrayList<>(), + classMethods + ); + testClass.getAnnotations().add( + new RenameAnnotation("renamedTestClass") + ); + + AnnotatedPythonModule testModule = + createAnnotatedPythonModule("testModule"); + testModule.getClasses().add(testClass); + + AnnotatedPythonPackage testPackage = + createAnnotatedPythonPackage("testPackage"); + testPackage.getModules().add(testModule); + + // when + testPackage.accept(renameAnnotationProcessor); + AnnotatedPythonPackage modifiedPackage = + renameAnnotationProcessor.getModifiedPackage(); + + // then + AnnotatedPythonParameter renamedParameter = modifiedPackage + .getModules().get(0) + .getClasses().get(0). + getMethods().get(0) + .getParameters().get(0); + Assertions.assertEquals( + "renamedTestParameter", + renamedParameter.getName() + ); + Assertions.assertEquals( + "testModule.renamedTestClass.renamedTestFunction.renamedTestParameter", + renamedParameter.getQualifiedName() + ); + } + + @Test + void shouldRenameGlobalFunctionParameterAndGlobalFunction() { + // given + RenameAnnotationProcessor renameAnnotationProcessor = + new RenameAnnotationProcessor(); + + AnnotatedPythonParameter pythonParameter = + createAnnotatedPythonParameter("testParameter"); + pythonParameter.getAnnotations().add( + new RenameAnnotation("renamedTestParameter") + ); + + AnnotatedPythonFunction testFunction = + createAnnotatedPythonFunction( + "testFunction", + "testModule.testFunction" + ); + testFunction.getParameters().add(pythonParameter); + testFunction.getAnnotations().add( + new RenameAnnotation("renamedTestFunction") + ); + + AnnotatedPythonModule testModule = + createAnnotatedPythonModule("testModule"); + testModule.getFunctions().add(testFunction); + + AnnotatedPythonPackage testPackage = + createAnnotatedPythonPackage("testPackage"); + testPackage.getModules().add(testModule); + + // when + testPackage.accept(renameAnnotationProcessor); + AnnotatedPythonPackage modifiedPackage = + renameAnnotationProcessor.getModifiedPackage(); + + // then + AnnotatedPythonParameter renamedParameter = modifiedPackage + .getModules().get(0) + .getFunctions().get(0) + .getParameters().get(0); + Assertions.assertEquals( + "renamedTestParameter", + renamedParameter.getName() + ); + Assertions.assertEquals( + "testModule.renamedTestFunction.renamedTestParameter", + renamedParameter.getQualifiedName() + ); + } +} diff --git a/server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/UnusedAnnotationProcessorTest.java b/server/src/test/java/com/larsreimann/api_editor/transformation/UnusedAnnotationProcessorTest.java similarity index 85% rename from server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/UnusedAnnotationProcessorTest.java rename to server/src/test/java/com/larsreimann/api_editor/transformation/UnusedAnnotationProcessorTest.java index 8a1164f03..e04e76eab 100644 --- a/server/src/test/java/com/larsreimann/api_editor/server/annotationProcessing/UnusedAnnotationProcessorTest.java +++ b/server/src/test/java/com/larsreimann/api_editor/transformation/UnusedAnnotationProcessorTest.java @@ -1,10 +1,17 @@ -package com.larsreimann.api_editor.server.annotationProcessing; +package com.larsreimann.api_editor.transformation; -import com.larsreimann.api_editor.server.data.*; +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonPackage; +import com.larsreimann.api_editor.model.UnusedAnnotation; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static com.larsreimann.api_editor.server.util.PackageDataFactoriesKt.*; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonClass; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonFunction; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonModule; +import static com.larsreimann.api_editor.util.PackageDataFactoriesKt.createAnnotatedPythonPackage; class UnusedAnnotationProcessorTest { @Test diff --git a/server/src/test/java/com/larsreimann/api_editor/server/validation/AnnotationValidationTest.java b/server/src/test/java/com/larsreimann/api_editor/validation/AnnotationValidationTest.java similarity index 95% rename from server/src/test/java/com/larsreimann/api_editor/server/validation/AnnotationValidationTest.java rename to server/src/test/java/com/larsreimann/api_editor/validation/AnnotationValidationTest.java index b9742b1e5..b4c2141c9 100644 --- a/server/src/test/java/com/larsreimann/api_editor/server/validation/AnnotationValidationTest.java +++ b/server/src/test/java/com/larsreimann/api_editor/validation/AnnotationValidationTest.java @@ -1,6 +1,25 @@ -package com.larsreimann.api_editor.server.validation; +package com.larsreimann.api_editor.validation; -import com.larsreimann.api_editor.server.data.*; +import com.larsreimann.api_editor.model.AnnotatedPythonClass; +import com.larsreimann.api_editor.model.AnnotatedPythonFunction; +import com.larsreimann.api_editor.model.AnnotatedPythonModule; +import com.larsreimann.api_editor.model.AnnotatedPythonPackage; +import com.larsreimann.api_editor.model.AnnotatedPythonParameter; +import com.larsreimann.api_editor.model.AnnotatedPythonResult; +import com.larsreimann.api_editor.model.AnnotationTarget; +import com.larsreimann.api_editor.model.AttributeAnnotation; +import com.larsreimann.api_editor.model.BoundaryAnnotation; +import com.larsreimann.api_editor.model.CalledAfterAnnotation; +import com.larsreimann.api_editor.model.ComparisonOperator; +import com.larsreimann.api_editor.model.ConstantAnnotation; +import com.larsreimann.api_editor.model.DefaultString; +import com.larsreimann.api_editor.model.GroupAnnotation; +import com.larsreimann.api_editor.model.MoveAnnotation; +import com.larsreimann.api_editor.model.OptionalAnnotation; +import com.larsreimann.api_editor.model.PythonFromImport; +import com.larsreimann.api_editor.model.PythonImport; +import com.larsreimann.api_editor.model.PythonParameterAssignment; +import com.larsreimann.api_editor.model.RenameAnnotation; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/server/src/test/kotlin/com/larsreimann/api_editor/codegen/ClassStubContentBuilderTest.kt b/server/src/test/kotlin/com/larsreimann/api_editor/codegen/ClassStubContentBuilderTest.kt new file mode 100644 index 000000000..f9343dc18 --- /dev/null +++ b/server/src/test/kotlin/com/larsreimann/api_editor/codegen/ClassStubContentBuilderTest.kt @@ -0,0 +1,162 @@ +package com.larsreimann.api_editor.codegen + +import com.larsreimann.api_editor.model.AnnotatedPythonClass +import com.larsreimann.api_editor.model.AnnotatedPythonFunction +import com.larsreimann.api_editor.model.AnnotatedPythonParameter +import com.larsreimann.api_editor.model.AttributeAnnotation +import com.larsreimann.api_editor.model.DefaultString +import com.larsreimann.api_editor.model.PythonParameterAssignment +import de.unibonn.simpleml.SimpleMLStandaloneSetup +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +internal class ClassStubContentBuilderTest { + + @BeforeEach + fun initSimpleML() { + SimpleMLStandaloneSetup.doSetup() + } + + @Test + fun buildClassReturnsFormattedClassWithNoConstructorAndFunctions() { + // given + val testClass = AnnotatedPythonClass( + "TestClass", + "testModule.TestClass", + listOf("TestDecorator"), + listOf("TestSuperclass"), emptyList(), + "Lorem ipsum", + "Lorem ipsum", mutableListOf() + ) + + // when + val classStubContentBuilder = ClassStubContentBuilder(testClass) + val formattedClass = classStubContentBuilder.buildClass() + + // then + val expectedFormattedClass = "class TestClass() {}" + Assertions.assertEquals(expectedFormattedClass, formattedClass) + } + + @Test + fun buildClassReturnsFormattedClassWithOneFunctionAndNoConstructor() { + // given + val testClass = AnnotatedPythonClass( + "TestClass", + "testModule.TestClass", + listOf("TestDecorator"), + listOf("TestSuperclass"), + listOf( + AnnotatedPythonFunction( + "testClassFunction", + "testModule.TestClass.testClassFunction", + listOf("decorators"), + listOf( + AnnotatedPythonParameter( + "onlyParam", + "testModule.TestClass.testClassFunction.onlyParam", + "'defaultValue'", + PythonParameterAssignment.POSITION_OR_NAME, + true, + "str", + "description", + mutableListOf( + AttributeAnnotation( + DefaultString("test") + ) + ) + ) + ), + emptyList(), + true, + "description", + "fullDocstring", mutableListOf() + ) + ), + "Lorem ipsum", + "Lorem ipsum", mutableListOf() + ) + + // when + val classStubContentBuilder = ClassStubContentBuilder(testClass) + val formattedClass = classStubContentBuilder.buildClass() + + // then + val expectedFormattedClass: String = """ + |class TestClass() { + | fun testClassFunction(onlyParam: String or "defaultValue") + |}""".trimMargin() + Assertions.assertEquals(expectedFormattedClass, formattedClass) + } + + @Test + fun buildClassReturnsFormattedClassWithConstructorAndOneFunction() { + // given + val testClass = AnnotatedPythonClass( + "TestClass", + "testModule.TestClass", + listOf("TestDecorator"), + listOf("TestSuperclass"), + listOf( + AnnotatedPythonFunction( + "testClassFunction1", + "testModule.TestClass.testClassFunction1", + listOf("decorators"), + listOf( + AnnotatedPythonParameter( + "onlyParam", + "testModule.TestClass.testClassFunction.onlyParam", + null, + PythonParameterAssignment.POSITION_OR_NAME, + true, + "typeInDocs", + "description", mutableListOf() + ) + ), + emptyList(), + true, + "description", + "fullDocstring", mutableListOf() + ), + AnnotatedPythonFunction( + "__init__", + "testModule.TestClass.__init__", + listOf("decorators"), + listOf( + AnnotatedPythonParameter( + "onlyParam", + "testModule.TestClass.__init__.onlyParam", + null, + PythonParameterAssignment.POSITION_OR_NAME, + true, + "typeInDocs", + "description", mutableListOf() + ) + ), + emptyList(), + true, + "description", + "fullDocstring", mutableListOf() + ) + ), + "Lorem ipsum", + "Lorem ipsum", mutableListOf() + ) + + // when + val classStubContentBuilder = ClassStubContentBuilder(testClass) + val formattedClass = classStubContentBuilder.buildClass() + + // then + val expectedFormattedClass: String = + """ + |class TestClass(onlyParam: Any?) { + | attr onlyParam: Any? + | + | fun testClassFunction1(onlyParam: Any?) + |}""".trimMargin() + + Assertions.assertEquals(formattedClass, expectedFormattedClass) + } +} diff --git a/server/src/test/kotlin/com/larsreimann/api_editor/codegen/FunctionStubContentBuilderTest.kt b/server/src/test/kotlin/com/larsreimann/api_editor/codegen/FunctionStubContentBuilderTest.kt new file mode 100644 index 000000000..ac8a382e7 --- /dev/null +++ b/server/src/test/kotlin/com/larsreimann/api_editor/codegen/FunctionStubContentBuilderTest.kt @@ -0,0 +1,306 @@ +package com.larsreimann.api_editor.codegen + +import com.larsreimann.api_editor.model.AnnotatedPythonFunction +import com.larsreimann.api_editor.model.AnnotatedPythonParameter +import com.larsreimann.api_editor.model.AnnotatedPythonResult +import com.larsreimann.api_editor.model.PythonParameterAssignment +import com.larsreimann.api_editor.util.createAnnotatedPythonFunction +import de.unibonn.simpleml.SimpleMLStandaloneSetup +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +internal class FunctionStubContentBuilderTest { + + @BeforeEach + fun initSimpleML() { + SimpleMLStandaloneSetup.doSetup() + } + + @Test + fun buildFunctionReturnsFormattedFunctionWithNoParameters() { + // given + val testFunction = AnnotatedPythonFunction( + "testFunction", + "testModule.testFunction", + listOf("test-decorator"), emptyList(), emptyList(), + true, + "Lorem ipsum", + "fullDocstring", mutableListOf() + ) + + // when + val functionStubContentBuilder = FunctionStubContentBuilder(testFunction) + val formattedFunction = functionStubContentBuilder.buildFunction() + + // then + val expectedFormattedFunction: String = + """ + |fun testFunction()""".trimMargin() + Assertions.assertEquals(expectedFormattedFunction, formattedFunction) + } + + @Test + fun buildFunctionReturnsFormattedFunctionWithPositionOnlyParameter() { + // given + val testFunction = AnnotatedPythonFunction( + "testFunction", + "testModule.testFunction", + listOf("test-decorator"), + listOf( + AnnotatedPythonParameter( + "onlyParam", + "testModule.test-class.testClassFunction.onlyParam", + "13", + PythonParameterAssignment.POSITION_ONLY, + true, + "int", + "description", mutableListOf() + ) + ), + emptyList(), + true, + "Lorem ipsum", + "fullDocstring", mutableListOf() + ) + + // when + val functionStubContentBuilder = FunctionStubContentBuilder(testFunction) + val formattedFunction = functionStubContentBuilder.buildFunction() + + // then + val expectedFormattedFunction: String = + """ + |fun testFunction(onlyParam: Int or 13)""".trimMargin() + Assertions.assertEquals(expectedFormattedFunction, formattedFunction) + } + + @Test + fun buildFunctionReturnsFormattedFunctionWithPositionOrNameParameter() { + // given + val testFunction = AnnotatedPythonFunction( + "testFunction", + "testModule.testFunction", + listOf("test-decorator"), + listOf( + AnnotatedPythonParameter( + "onlyParam", + "testModule.test-class.testClassFunction.onlyParam", + "'Test'", + PythonParameterAssignment.POSITION_OR_NAME, + true, + "string", + "description", mutableListOf() + ) + ), + emptyList(), + true, + "Lorem ipsum", + "fullDocstring", mutableListOf() + ) + + // when + val functionStubContentBuilder = FunctionStubContentBuilder(testFunction) + val formattedFunction = functionStubContentBuilder.buildFunction() + + // then + val expectedFormattedFunction: String = + """ + |fun testFunction(onlyParam: Any? or "Test")""".trimMargin() + Assertions.assertEquals(expectedFormattedFunction, formattedFunction) + } + + @Test + fun buildFunctionReturnsFormattedFunctionWithPositionAndPositionOrNameAndNameOnlyParameter() { + // given + val testFunction = AnnotatedPythonFunction( + "testFunction", + "testModule.testFunction", + listOf("test-decorator"), + listOf( + AnnotatedPythonParameter( + "firstParam", + "testModule.test-class.testClassFunction.firstParam", + null, + PythonParameterAssignment.POSITION_ONLY, + true, + "typeInDocs", + "description", mutableListOf() + ), + AnnotatedPythonParameter( + "secondParam", + "testModule.test-class.testClassFunction.secondParam", + null, + PythonParameterAssignment.POSITION_OR_NAME, + true, + "typeInDocs", + "description", mutableListOf() + ), + AnnotatedPythonParameter( + "thirdParam", + "testModule.test-class.testClassFunction.thirdParam", + null, + PythonParameterAssignment.NAME_ONLY, + true, + "typeInDocs", + "description", mutableListOf() + ) + ), + emptyList(), + true, + "Lorem ipsum", + "fullDocstring", mutableListOf() + ) + + // when + val functionStubContentBuilder = FunctionStubContentBuilder(testFunction) + val formattedFunction = functionStubContentBuilder.buildFunction() + + // then + val expectedFormattedFunction: String = """ + |fun testFunction(firstParam: Any?, secondParam: Any?, thirdParam: Any?)""".trimMargin() + Assertions.assertEquals(expectedFormattedFunction, formattedFunction) + } + + @Test + fun buildFunctionReturnsFormattedFunctionWithOneResult() { + // given + val testFunction = AnnotatedPythonFunction( + "testFunction", + "testModule.testFunction", + listOf("test-decorator"), + listOf( + AnnotatedPythonParameter( + "onlyParam", + "testModule.test-class.testClassFunction.onlyParam", + "1.31e+1", + PythonParameterAssignment.POSITION_ONLY, + true, + "float", + "description", mutableListOf() + ) + ), + listOf( + AnnotatedPythonResult( + "firstResult", + "float", + "float", + "description", mutableListOf() + ) + ), + true, + "Lorem ipsum", + "fullDocstring", mutableListOf() + ) + + // when + val functionStubContentBuilder = FunctionStubContentBuilder(testFunction) + val formattedFunction = functionStubContentBuilder.buildFunction() + + // then + val expectedFormattedFunction: String = """ + |fun testFunction(onlyParam: Float or 13.1) -> firstResult: Float""".trimMargin() + Assertions.assertEquals(expectedFormattedFunction, formattedFunction) + } + + @Test + fun buildFunctionReturnsFormattedFunctionWithMultipleResults() { + // given + val testFunction = AnnotatedPythonFunction( + "testFunction", + "testModule.testFunction", + listOf("test-decorator"), + listOf( + AnnotatedPythonParameter( + "onlyParam", + "testModule.test-class.testClassFunction.onlyParam", + "True", + PythonParameterAssignment.POSITION_ONLY, + true, + "bool", + "description", mutableListOf() + ) + ), + listOf( + AnnotatedPythonResult( + "firstResult", + "float", + "float", + "description", mutableListOf() + ), + AnnotatedPythonResult( + "secondResult", + "float", + "float", + "description", mutableListOf() + ) + ), + true, + "Lorem ipsum", + "fullDocstring", mutableListOf() + ) + + // when + val functionStubContentBuilder = FunctionStubContentBuilder(testFunction) + val formattedFunction = functionStubContentBuilder.buildFunction() + + // then + val expectedFormattedFunction: String = """ + |fun testFunction(onlyParam: Boolean or true) -> (firstResult: Float, secondResult: Float)""".trimMargin() + Assertions.assertEquals(expectedFormattedFunction, formattedFunction) + } + + @Test + fun buildFunctionReturnsFormattedFunctionWithInvalidDefaultValue() { + // given + val testFunction = AnnotatedPythonFunction( + "testFunction", + "testModule.testFunction", + listOf("test-decorator"), + listOf( + AnnotatedPythonParameter( + "onlyParam", + "testModule.test-class.testClassFunction.onlyParam", + "'13'x", + PythonParameterAssignment.POSITION_ONLY, + true, + "string", + "description", mutableListOf() + ) + ), + emptyList(), + true, + "Lorem ipsum", + "fullDocstring", mutableListOf() + ) + + // when + val functionStubContentBuilder = FunctionStubContentBuilder(testFunction) + val formattedFunction = functionStubContentBuilder.buildFunction() + + // then + val expectedFormattedFunction: String = """ + |fun testFunction(onlyParam: Any? or "###invalid###'13'x###")""".trimMargin() + Assertions.assertEquals(expectedFormattedFunction, formattedFunction) + } + + @Test + fun shouldMarkPureFunctionsWithAnnotation() { + // given + val testFunction = createAnnotatedPythonFunction( + "testFunction" + ) + testFunction.isPure = true + + // when + val functionStubContentBuilder = FunctionStubContentBuilder(testFunction) + val formattedFunction = functionStubContentBuilder.buildFunction() + + // then + val expectedFormattedFunction: String = """ + |@Pure + |fun testFunction()""".trimMargin() + + Assertions.assertEquals(expectedFormattedFunction, formattedFunction) + } +} diff --git a/server/src/test/kotlin/com/larsreimann/api_editor/codegen/ModuleStubContentBuilderTest.kt b/server/src/test/kotlin/com/larsreimann/api_editor/codegen/ModuleStubContentBuilderTest.kt new file mode 100644 index 000000000..2edf53c21 --- /dev/null +++ b/server/src/test/kotlin/com/larsreimann/api_editor/codegen/ModuleStubContentBuilderTest.kt @@ -0,0 +1,364 @@ +package com.larsreimann.api_editor.codegen + +import com.larsreimann.api_editor.model.AnnotatedPythonClass +import com.larsreimann.api_editor.model.AnnotatedPythonFunction +import com.larsreimann.api_editor.model.AnnotatedPythonModule +import com.larsreimann.api_editor.model.AnnotatedPythonParameter +import com.larsreimann.api_editor.model.AnnotatedPythonResult +import com.larsreimann.api_editor.model.PythonFromImport +import com.larsreimann.api_editor.model.PythonImport +import com.larsreimann.api_editor.model.PythonParameterAssignment +import de.unibonn.simpleml.SimpleMLStandaloneSetup +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +internal class ModuleStubContentBuilderTest { + + @BeforeEach + fun initSimpleML() { + SimpleMLStandaloneSetup.doSetup() + } + + @Test + fun buildModuleContentReturnsFormattedModuleContent() { + // given + val testClass = AnnotatedPythonClass( + "testClass", + "testModule.testClass", + listOf("test-decorator"), + listOf("test-superclass"), + listOf( + AnnotatedPythonFunction( + "testClassFunction", + "testModule.testClass.testClassFunction", + listOf("decorators"), + listOf( + AnnotatedPythonParameter( + "onlyParam", + "testModule.testClass.testClassFunction.onlyParam", + "'defaultValue'", + PythonParameterAssignment.POSITION_OR_NAME, + true, + "typeInDocs", + "description", + mutableListOf() + ) + ), + emptyList(), + true, + "description", + "fullDocstring", + mutableListOf() + ), + AnnotatedPythonFunction( + "__init__", + "testModule.testClass.__init__", + listOf("decorators"), + listOf( + AnnotatedPythonParameter( + "onlyParam", + "testModule.testClass.__init__.onlyParam", + "'defaultValue'", + PythonParameterAssignment.POSITION_OR_NAME, + true, + "typeInDocs", + "description", mutableListOf() + ) + ), + emptyList(), + true, + "description", + "fullDocstring", mutableListOf() + ) + ), + "Lorem ipsum", + "Lorem ipsum", mutableListOf() + ) + val testModule = AnnotatedPythonModule( + "testModule", emptyList(), emptyList(), + listOf( + testClass + ), + listOf( + AnnotatedPythonFunction( + "function_module_1", + "test.module_1.function_module_1", + listOf("test-decorator"), + listOf( + AnnotatedPythonParameter( + "param1", + "test.module_1.function_module_1.param1", + null, + PythonParameterAssignment.NAME_ONLY, + true, + "str", + "Lorem ipsum", mutableListOf() + ), + AnnotatedPythonParameter( + "param2", + "test.module_1.function_module_1.param2", + null, + PythonParameterAssignment.NAME_ONLY, + true, + "str", + "Lorem ipsum", mutableListOf() + ), + AnnotatedPythonParameter( + "param3", + "test.module_1.function_module_1.param3", + null, + PythonParameterAssignment.NAME_ONLY, + true, + "str", + "Lorem ipsum", mutableListOf() + ) + ), + listOf( + AnnotatedPythonResult( + "testResult", + "str", + "str", + "Lorem ipsum", mutableListOf() + ) + ), + true, + "Lorem ipsum", + "Lorem ipsum", mutableListOf() + ), + AnnotatedPythonFunction( + "testFunction", + "testModule.testFunction", + listOf("test-decorator"), + listOf( + AnnotatedPythonParameter( + "testParameter", + "testModule.testFunction.testParameter", + "42", + PythonParameterAssignment.NAME_ONLY, + true, + "int", + "Lorem ipsum", mutableListOf() + ) + ), + listOf( + AnnotatedPythonResult( + "testResult", + "str", + "str", + "Lorem ipsum", mutableListOf() + ) + ), + true, + "Lorem ipsum", + "Lorem ipsum", mutableListOf() + ) + ), + mutableListOf() + ) + + // when + val moduleStubContentBuilder = ModuleStubContentBuilder(testModule) + val moduleContent = moduleStubContentBuilder.buildModuleContent() + + // then + val expectedModuleContent: String = """ + |package simpleml.testModule + | + |class testClass(onlyParam: Any? or "defaultValue") { + | attr onlyParam: Any? + | + | fun testClassFunction(onlyParam: Any? or "defaultValue") + |} + | + |fun function_module_1(param1: String, param2: String, param3: String) -> testResult: String + | + |fun testFunction(testParameter: Int or 42) -> testResult: String + |""".trimMargin() + Assertions.assertEquals(expectedModuleContent, moduleContent) + } + + @Test + fun buildModuleContentWithNoClassesReturnsFormattedModuleContent() { + // given + val testModule = AnnotatedPythonModule( + "testModule", emptyList(), emptyList(), emptyList(), + listOf( + AnnotatedPythonFunction( + "function_module_1", + "test.module_1.function_module_1", + listOf("test-decorator"), + listOf( + AnnotatedPythonParameter( + "param1", + "test.module_1.function_module_1.param1", + null, + PythonParameterAssignment.NAME_ONLY, + true, + "str", + "Lorem ipsum", mutableListOf() + ), + AnnotatedPythonParameter( + "param2", + "test.module_1.function_module_1.param2", + null, + PythonParameterAssignment.NAME_ONLY, + true, + "str", + "Lorem ipsum", mutableListOf() + ), + AnnotatedPythonParameter( + "param3", + "test.module_1.function_module_1.param3", + null, + PythonParameterAssignment.NAME_ONLY, + true, + "str", + "Lorem ipsum", mutableListOf() + ) + ), + listOf( + AnnotatedPythonResult( + "testResult", + "str", + "str", + "Lorem ipsum", mutableListOf() + ) + ), + true, + "Lorem ipsum", + "Lorem ipsum", mutableListOf() + ), + AnnotatedPythonFunction( + "testFunction", + "testModule.testFunction", + listOf("test-decorator"), + listOf( + AnnotatedPythonParameter( + "testParameter", + "testModule.testFunction.testParameter", + "42", + PythonParameterAssignment.NAME_ONLY, + true, + "int", + "Lorem ipsum", mutableListOf() + ) + ), + listOf( + AnnotatedPythonResult( + "testResult", + "str", + "str", + "Lorem ipsum", mutableListOf() + ) + ), + true, + "Lorem ipsum", + "Lorem ipsum", mutableListOf() + ) + ), + mutableListOf() + ) + + // when + val moduleStubContentBuilder = ModuleStubContentBuilder(testModule) + val moduleContent = moduleStubContentBuilder.buildModuleContent() + + // then + val expectedModuleContent: String = """ + |package simpleml.testModule + | + |fun function_module_1(param1: String, param2: String, param3: String) -> testResult: String + | + |fun testFunction(testParameter: Int or 42) -> testResult: String + |""".trimMargin() + Assertions.assertEquals(expectedModuleContent, moduleContent) + } + + @Test + fun buildModuleContentWithOnlyConstructorReturnsFormattedModuleContent() { + // given + val testClass = AnnotatedPythonClass( + "testClass", + "testModule.testClass", + listOf("test-decorator"), + listOf("test-superclass"), + listOf( + AnnotatedPythonFunction( + "__init__", + "testModule.testClass.__init__", + listOf("decorators"), + listOf( + AnnotatedPythonParameter( + "onlyParam", + "testModule.testClass.__init__.onlyParam", + "'defaultValue'", + PythonParameterAssignment.POSITION_OR_NAME, + true, + "typeInDocs", + "description", mutableListOf() + ) + ), + emptyList(), + true, + "description", + "fullDocstring", mutableListOf() + ) + ), + "Lorem ipsum", + "Lorem ipsum", mutableListOf() + ) + val testModule = AnnotatedPythonModule( + "testModule", + listOf( + PythonImport( + "test-import1", + "test-alias" + ) + ), + listOf( + PythonFromImport( + "test-from-import1", + "test-declaration1", + null + ) + ), + listOf( + testClass + ), + emptyList(), mutableListOf() + ) + + // when + val moduleStubContentBuilder = ModuleStubContentBuilder(testModule) + val moduleContent = moduleStubContentBuilder.buildModuleContent() + + // then + val expectedModuleContent: String = """ + |package simpleml.testModule + | + |class testClass(onlyParam: Any? or "defaultValue") { + | attr onlyParam: Any? + |} + |""".trimMargin() + Assertions.assertEquals(expectedModuleContent, moduleContent) + } + + @Test + fun buildModuleContentWithNoFunctionsAndClassesReturnsFormattedModuleContent() { + // given + val testModule = AnnotatedPythonModule( + "testModule", emptyList(), emptyList(), emptyList(), emptyList(), mutableListOf() + ) + + // when + val moduleStubContentBuilder = ModuleStubContentBuilder(testModule) + val moduleContent = moduleStubContentBuilder.buildModuleContent() + + // then + val expectedModuleContent: String = """ + |package simpleml.testModule + |""".trimMargin() + Assertions.assertEquals(expectedModuleContent, moduleContent) + } +} diff --git a/server/src/test/kotlin/com/larsreimann/api_editor/server/ApplicationTest.kt b/server/src/test/kotlin/com/larsreimann/api_editor/server/ApplicationTest.kt index bedb21b89..366bcc04d 100644 --- a/server/src/test/kotlin/com/larsreimann/api_editor/server/ApplicationTest.kt +++ b/server/src/test/kotlin/com/larsreimann/api_editor/server/ApplicationTest.kt @@ -1,31 +1,31 @@ package com.larsreimann.api_editor.server -import com.larsreimann.api_editor.server.data.AnnotatedPythonClass -import com.larsreimann.api_editor.server.data.AnnotatedPythonFunction -import com.larsreimann.api_editor.server.data.AnnotatedPythonModule -import com.larsreimann.api_editor.server.data.AnnotatedPythonPackage -import com.larsreimann.api_editor.server.data.AnnotatedPythonParameter -import com.larsreimann.api_editor.server.data.AnnotatedPythonResult -import com.larsreimann.api_editor.server.data.AttributeAnnotation -import com.larsreimann.api_editor.server.data.BoundaryAnnotation -import com.larsreimann.api_editor.server.data.CalledAfterAnnotation -import com.larsreimann.api_editor.server.data.ComparisonOperator -import com.larsreimann.api_editor.server.data.ConstantAnnotation -import com.larsreimann.api_editor.server.data.DefaultBoolean -import com.larsreimann.api_editor.server.data.DefaultNumber -import com.larsreimann.api_editor.server.data.DefaultString -import com.larsreimann.api_editor.server.data.EnumAnnotation -import com.larsreimann.api_editor.server.data.EnumPair -import com.larsreimann.api_editor.server.data.GroupAnnotation -import com.larsreimann.api_editor.server.data.MoveAnnotation -import com.larsreimann.api_editor.server.data.OptionalAnnotation -import com.larsreimann.api_editor.server.data.PureAnnotation -import com.larsreimann.api_editor.server.data.PythonFromImport -import com.larsreimann.api_editor.server.data.PythonImport -import com.larsreimann.api_editor.server.data.PythonParameterAssignment -import com.larsreimann.api_editor.server.data.RenameAnnotation -import com.larsreimann.api_editor.server.data.RequiredAnnotation -import com.larsreimann.api_editor.server.data.UnusedAnnotation +import com.larsreimann.api_editor.model.AnnotatedPythonClass +import com.larsreimann.api_editor.model.AnnotatedPythonFunction +import com.larsreimann.api_editor.model.AnnotatedPythonModule +import com.larsreimann.api_editor.model.AnnotatedPythonPackage +import com.larsreimann.api_editor.model.AnnotatedPythonParameter +import com.larsreimann.api_editor.model.AnnotatedPythonResult +import com.larsreimann.api_editor.model.AttributeAnnotation +import com.larsreimann.api_editor.model.BoundaryAnnotation +import com.larsreimann.api_editor.model.CalledAfterAnnotation +import com.larsreimann.api_editor.model.ComparisonOperator +import com.larsreimann.api_editor.model.ConstantAnnotation +import com.larsreimann.api_editor.model.DefaultBoolean +import com.larsreimann.api_editor.model.DefaultNumber +import com.larsreimann.api_editor.model.DefaultString +import com.larsreimann.api_editor.model.EnumAnnotation +import com.larsreimann.api_editor.model.EnumPair +import com.larsreimann.api_editor.model.GroupAnnotation +import com.larsreimann.api_editor.model.MoveAnnotation +import com.larsreimann.api_editor.model.OptionalAnnotation +import com.larsreimann.api_editor.model.PureAnnotation +import com.larsreimann.api_editor.model.PythonFromImport +import com.larsreimann.api_editor.model.PythonImport +import com.larsreimann.api_editor.model.PythonParameterAssignment +import com.larsreimann.api_editor.model.RenameAnnotation +import com.larsreimann.api_editor.model.RequiredAnnotation +import com.larsreimann.api_editor.model.UnusedAnnotation import io.ktor.http.ContentType import io.ktor.http.HttpHeaders import io.ktor.http.HttpMethod diff --git a/server/src/test/kotlin/com/larsreimann/api_editor/server/annotationProcessing/OriginalDeclarationProcessorTest.kt b/server/src/test/kotlin/com/larsreimann/api_editor/transformation/OriginalDeclarationProcessorTest.kt similarity index 87% rename from server/src/test/kotlin/com/larsreimann/api_editor/server/annotationProcessing/OriginalDeclarationProcessorTest.kt rename to server/src/test/kotlin/com/larsreimann/api_editor/transformation/OriginalDeclarationProcessorTest.kt index 52ab5794f..dec6284e2 100644 --- a/server/src/test/kotlin/com/larsreimann/api_editor/server/annotationProcessing/OriginalDeclarationProcessorTest.kt +++ b/server/src/test/kotlin/com/larsreimann/api_editor/transformation/OriginalDeclarationProcessorTest.kt @@ -1,10 +1,10 @@ -package com.larsreimann.api_editor.server.annotationProcessing +package com.larsreimann.api_editor.transformation -import com.larsreimann.api_editor.server.data.UnusedAnnotation -import com.larsreimann.api_editor.server.util.createAnnotatedPythonClass -import com.larsreimann.api_editor.server.util.createAnnotatedPythonFunction -import com.larsreimann.api_editor.server.util.createAnnotatedPythonModule -import com.larsreimann.api_editor.server.util.createAnnotatedPythonPackage +import com.larsreimann.api_editor.model.UnusedAnnotation +import com.larsreimann.api_editor.util.createAnnotatedPythonClass +import com.larsreimann.api_editor.util.createAnnotatedPythonFunction +import com.larsreimann.api_editor.util.createAnnotatedPythonModule +import com.larsreimann.api_editor.util.createAnnotatedPythonPackage import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test diff --git a/server/src/test/kotlin/com/larsreimann/api_editor/server/annotationProcessing/PureAnnotationProcessorTest.kt b/server/src/test/kotlin/com/larsreimann/api_editor/transformation/PureAnnotationProcessorTest.kt similarity index 80% rename from server/src/test/kotlin/com/larsreimann/api_editor/server/annotationProcessing/PureAnnotationProcessorTest.kt rename to server/src/test/kotlin/com/larsreimann/api_editor/transformation/PureAnnotationProcessorTest.kt index 6c484e772..ceed9e139 100644 --- a/server/src/test/kotlin/com/larsreimann/api_editor/server/annotationProcessing/PureAnnotationProcessorTest.kt +++ b/server/src/test/kotlin/com/larsreimann/api_editor/transformation/PureAnnotationProcessorTest.kt @@ -1,9 +1,9 @@ -package com.larsreimann.api_editor.server.annotationProcessing +package com.larsreimann.api_editor.transformation -import com.larsreimann.api_editor.server.data.PureAnnotation -import com.larsreimann.api_editor.server.util.createAnnotatedPythonFunction -import com.larsreimann.api_editor.server.util.createAnnotatedPythonModule -import com.larsreimann.api_editor.server.util.createAnnotatedPythonPackage +import com.larsreimann.api_editor.model.PureAnnotation +import com.larsreimann.api_editor.util.createAnnotatedPythonFunction +import com.larsreimann.api_editor.util.createAnnotatedPythonModule +import com.larsreimann.api_editor.util.createAnnotatedPythonPackage import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test