/** * Copyright 2013-2019 the original author or authors from the Jeddict project (https://jeddict.github.io/). * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package io.github.jeddict.test; import com.github.javaparser.JavaParser; import com.github.javaparser.ParseProblemException; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.printer.PrettyPrinter; import static io.github.jeddict.jcode.console.Console.BOLD; import static io.github.jeddict.jcode.console.Console.FG_DARK_BLUE; import static io.github.jeddict.jcode.console.Console.FG_DARK_CYAN; import static io.github.jeddict.jcode.console.Console.FG_DARK_GREEN; import static io.github.jeddict.jcode.console.Console.FG_DARK_MAGENTA; import static io.github.jeddict.jcode.console.Console.FG_DARK_RED; import static io.github.jeddict.jcode.console.Console.FG_DARK_YELLOW; import static io.github.jeddict.jcode.console.Console.FG_RED; import static io.github.jeddict.jcode.console.Console.wrap; import static io.github.jeddict.jcode.util.Constants.JAVA_EXT; import static io.github.jeddict.jcode.util.Constants.JAVA_EXT_SUFFIX; import static io.github.jeddict.jcode.util.FileUtil.readString; import static io.github.jeddict.jcode.util.ProjectHelper.getFileObject; import io.github.jeddict.jpa.modeler.initializer.JPAModelerUtil; import static io.github.jeddict.jpa.modeler.initializer.JPAModelerUtil.getEntityMapping; import io.github.jeddict.jpa.spec.DefaultClass; import io.github.jeddict.jpa.spec.Embeddable; import io.github.jeddict.jpa.spec.Entity; import io.github.jeddict.jpa.spec.EntityMappings; import io.github.jeddict.jpa.spec.MappedSuperclass; import io.github.jeddict.jpa.spec.bean.BeanClass; import io.github.jeddict.jpa.spec.extend.JavaClass; import io.github.jeddict.jpa.spec.sync.JavaClassSyncHandler; import io.github.jeddict.orm.generator.compiler.def.ClassDefSnippet; import io.github.jeddict.orm.generator.service.BeanClassGenerator; import io.github.jeddict.orm.generator.service.ClassGenerator; import io.github.jeddict.orm.generator.service.DefaultClassGenerator; import io.github.jeddict.orm.generator.service.EmbeddableGenerator; import io.github.jeddict.orm.generator.service.EmbeddableIdClassGenerator; import io.github.jeddict.orm.generator.service.EntityGenerator; import io.github.jeddict.orm.generator.service.MappedSuperClassGenerator; import io.github.jeddict.orm.generator.util.ORMConverterUtil; import io.github.jeddict.reveng.klass.ClassWizardDescriptor; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringReader; import java.net.URISyntaxException; import java.net.URL; import static java.nio.charset.StandardCharsets.UTF_8; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import javax.xml.bind.JAXBException; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import org.netbeans.api.project.Project; import org.netbeans.modules.j2ee.persistence.wizard.jpacontroller.ProgressReporter; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; import org.openide.util.Utilities; /** * Test flow : * <br> * - Parse the model * <br> * - Generates the source code * <br> * - Validate using java parser for compilation issue * <br> * - Compare with the existing source * * @author jGauravGupta */ public class BaseModelTest { protected void testModelerFile(String fileName) throws Exception { EntityMappings entityMappings = loadEntityMappings(fileName); assertNotNull(entityMappings); fileName = fileName.substring(0, fileName.lastIndexOf('.')); generateClasses(entityMappings, fileName); } protected void generateClasses(EntityMappings entityMappings, FileObject sourceGroup) throws Exception { File sourceRoot = FileUtil.toFile(sourceGroup); String packageName = entityMappings.getPackage(); for (Entity clazz : entityMappings.getEntity()) { generateClass(new EntityGenerator(clazz, packageName), entityMappings, sourceRoot); } for (MappedSuperclass clazz : entityMappings.getMappedSuperclass()) { generateClass(new MappedSuperClassGenerator(clazz, packageName), entityMappings, sourceRoot); } for (Embeddable clazz : entityMappings.getEmbeddable()) { generateClass(new EmbeddableGenerator(clazz, packageName), entityMappings, sourceRoot); } for (DefaultClass clazz : entityMappings.getDefaultClass()) { if (clazz.isEmbeddable()) { generateClass(new EmbeddableIdClassGenerator(clazz, packageName), entityMappings, sourceRoot); } else { generateClass(new DefaultClassGenerator(clazz, packageName), entityMappings, sourceRoot); } } for (BeanClass clazz : entityMappings.getBeanClass()) { generateClass(new BeanClassGenerator(clazz, packageName), entityMappings, sourceRoot); } } private void generateClass(ClassGenerator generator, EntityMappings entityMappings, File sourceRoot) throws Exception { ClassDefSnippet classDef = generator.getClassDef(); classDef.setJaxbSupport(entityMappings.getJaxbSupport()); classDef.getSnippet(); ORMConverterUtil.writeSnippet(classDef, sourceRoot); } protected void generateClasses(EntityMappings entityMappings, String fileName) throws Exception { String packageName = this.getClass().getPackage().getName(); for (Entity clazz : entityMappings.getEntity()) { testClass(clazz, new EntityGenerator(clazz, packageName), entityMappings, fileName); } for (MappedSuperclass clazz : entityMappings.getMappedSuperclass()) { testClass(clazz, new MappedSuperClassGenerator(clazz, packageName), entityMappings, fileName); } for (Embeddable clazz : entityMappings.getEmbeddable()) { testClass(clazz, new EmbeddableGenerator(clazz, packageName), entityMappings, fileName); } for (DefaultClass clazz : entityMappings.getDefaultClass()) { if (clazz.isEmbeddable()) { testClass(clazz, new EmbeddableIdClassGenerator(clazz, packageName), entityMappings, fileName); } else { testClass(clazz, new DefaultClassGenerator(clazz, packageName), entityMappings, fileName); } } for (BeanClass clazz : entityMappings.getBeanClass()) { testClass(clazz, new BeanClassGenerator(clazz, packageName), entityMappings, fileName); } } private void testClass(JavaClass javaClass, ClassGenerator generator, EntityMappings entityMappings, String fileName) throws Exception { PrettyPrinter prettyPrinter = new PrettyPrinter(); String existingSource; CompilationUnit existingUnit; String newSource = null; CompilationUnit newUnit; try (InputStream existingSourceStream = this.getClass().getResourceAsStream(javaClass.getClazz() + JAVA_EXT_SUFFIX)) { existingSource = readString(existingSourceStream); existingUnit = new JavaParser().parse(existingSource).getResult().get(); assertNotNull(existingUnit); existingSource = prettyPrinter.print(existingUnit); } JavaClassSyncHandler .getInstance(javaClass) .syncExistingSnippet(existingUnit); if (fileName == null) { fileName = wrap("Reverse Engineering", FG_DARK_MAGENTA); } else { fileName = wrap(fileName, FG_DARK_BLUE); } try { ClassDefSnippet classDef = generator.getClassDef(); classDef.setJaxbSupport(entityMappings.getJaxbSupport()); newSource = classDef.getSnippet(); assertNotNull(newSource); newUnit = new JavaParser().parse(newSource).getResult().get(); assertNotNull(newUnit); newSource = prettyPrinter.print(newUnit); // System.out.println("newSource " + newSource); try (BufferedReader existingSourceReader = new BufferedReader(new StringReader(existingSource)); BufferedReader newSourceReader = new BufferedReader(new StringReader(newSource));) { String existingSourceLine; String newSourceLine; int lineNumber = 0; while ((existingSourceLine = existingSourceReader.readLine()) != null && (newSourceLine = newSourceReader.readLine()) != null) { ++lineNumber; assertEquals(existingSourceLine, newSourceLine, '\n' + wrap("Failed : " + javaClass.getFQN() + " [" + fileName + "]", FG_DARK_RED, BOLD) + '\n' + wrap("Line number : " + lineNumber, FG_RED, BOLD) + '\n' + wrap("existingSourceLine : " + existingSourceLine, FG_DARK_RED) + '\n' + wrap("newSourceLine : " + newSourceLine, FG_DARK_RED) + '\n' + newSource ); } } System.out.println(wrap("Passed : ", FG_DARK_GREEN, BOLD) + wrap(javaClass.getFQN(), FG_DARK_CYAN) + " [" + fileName + "]" ); } catch (ParseProblemException ex) { fail(wrap( "Compilation Failed : " + javaClass.getFQN() + " [" + fileName + "]" + '\n' + "---------------------" + '\n' + newSource + '\n' + "---------------------" + ex.getMessage() + "---------------------", FG_RED )); } } protected void reverseEngineeringTest(String... classes) { try { ProjectBuilder projectBuilder = new ProjectBuilder("reverse-engineering-test"); FileObject src = projectBuilder.getSrc(); EntityMappings entityMappings = createEntityMappings(); String packageName = this.getClass().getPackage().getName(); Set<String> classFqns = new HashSet<>(); for (String clazz : classes) { FileObject classPackage = getFileObject(src, packageName, "\\."); classFqns.add(packageName + '.' + clazz); File classFile = Utilities.toFile(this.getClass().getResource(clazz + JAVA_EXT_SUFFIX).toURI()); FileObject classFileObject = FileUtil.toFileObject(classFile); classFileObject.copy(classPackage, clazz, JAVA_EXT); } ClassWizardDescriptor descriptor = new ClassWizardDescriptor(); descriptor.loadSource(getProgressReporter(), entityMappings, src, classFqns, false); generateClasses(entityMappings, (String) null); } catch (Exception ex) { fail(Arrays.toString(classes) + " reverse engineering failed", ex); } } protected EntityMappings createEntityMappings() throws IOException { String packageName = this.getClass().getPackage().getName(); EntityMappings entityMappings = EntityMappings.getNewInstance(JPAModelerUtil.getModelerFileVersion()); entityMappings.setEntityPackage(packageName); return entityMappings; } protected EntityMappings loadEntityMappings(String fileName) { try { URL resource = this.getClass().getResource(fileName); assertNotNull(resource, fileName + " not found"); File file = Utilities.toFile(resource.toURI()); return getEntityMapping(file); } catch (JAXBException ex) { fail(fileName + " file jaxb parsing error", ex); } catch (URISyntaxException ex) { fail(fileName + " file uri syntax error", ex); } catch (IOException ex) { fail(fileName, ex); } throw new IllegalStateException("Unable to load file : " + fileName); } protected ProgressReporter getProgressReporter() { return (message, index) -> System.out.println(wrap(message, FG_DARK_YELLOW)); } /** * Create a new data file with specified initial contents.No file events * should be fired until the resulting file is complete (see * {@link FileObject#createAndOpen}). * * @param root a root folder which should already exist * @param path a /-separated path to the new file within that root * @param body the complete contents of the new file (in UTF-8 encoding) * @return * @throws java.io.IOException */ public static FileObject writeFile(FileObject root, String path, String body) throws IOException { int slash = path.lastIndexOf('/'); if (slash != -1) { root = FileUtil.createFolder(root, path.substring(0, slash)); path = path.substring(slash + 1); } FileObject existing = root.getFileObject(path); OutputStream os = existing != null ? existing.getOutputStream() : root.createAndOpen(path); try { PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, UTF_8)); pw.print(body); pw.flush(); } finally { os.close(); } return root.getFileObject(path); } // protected InvocationResult fireMavenBuild(Project project, List<String> goals, List<String> profiles, Properties properties) { // InvocationResult result = null; // try { // String mavenHome = System.getenv("M2_HOME"); // if (mavenHome == null) { // mavenHome = System.getenv("MAVEN_HOME"); // } // InvocationRequest request = new DefaultInvocationRequest(); // request.setPomFile(new File(project.getProjectDirectory().getPath() + "/pom.xml")); // System.out.println("Project : " + request.getPomFile().getAbsolutePath()); // request.setGoals(goals); // request.setProfiles(profiles); // request.setProperties(properties); // // Invoker invoker = new DefaultInvoker(); // invoker.setMavenHome(new File(mavenHome)); // System.out.println("Maven Home : " + mavenHome); // result = invoker.execute(request); // assertEquals(0, result.getExitCode(), "Maven build failed : " + result.getExecutionException().getMessage()); // } catch (Exception ex) { // ex.printStackTrace(); // fail("Maven build failed", ex); // } // return result; // } protected int fireMavenBuild(Project project, List<String> goals, List<String> profiles, Properties properties) { int code = 0; String mavenHome = System.getenv("M2_HOME"); if (mavenHome == null) { mavenHome = System.getenv("MAVEN_HOME"); } if (mavenHome == null) { throw new IllegalStateException("MAVEN_HOME or M2_HOME path not defined"); } try { String cmd = (System.getProperty("os.name").startsWith("Windows")) ? "mvn.cmd" : "mvn"; cmd = mavenHome + File.separator + "bin" + File.separator + cmd; List<String> args = new ArrayList<>(); args.add(cmd); args.add("-B"); if (goals != null && !goals.isEmpty()) { args.addAll(goals); } if (profiles != null && !profiles.isEmpty()) { args.add("-P"); args.addAll(profiles); } if (properties != null) { properties.entrySet().forEach(e -> args.add("-D" + e.getKey() + "=" + e.getValue())); } ProcessBuilder pb = new ProcessBuilder(args.toArray(new String[]{})); pb.directory(FileUtil.toFile(project.getProjectDirectory())); Process process = pb.start(); redirectOutput(process.getInputStream(), System.out); redirectOutput(process.getErrorStream(), System.err); code = process.waitFor(); if (code != 0) { assertEquals(0, code, "Maven Process build failed : " + code); } } catch (Exception ex) { ex.printStackTrace(); fail("Maven Process build failed", ex); } return code; } private void redirectOutput(final InputStream input, final PrintStream output) { new Thread(() -> { StringBuilder sb = new StringBuilder(); String line; try (BufferedReader reader = new BufferedReader(new InputStreamReader(input))) { while ((line = reader.readLine()) != null) { sb.append(line); output.println(line); } } catch (IOException ex) { ex.printStackTrace(); } }).start(); } }