package com.josketres.builderator;

import org.assertj.core.api.JUnitSoftAssertions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
import test.classes.NormalJavaBean;
import test.classes.ParentBuilderClass;
import test.classes.pkg.ParentBuilderClassOtherPackage;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import static com.josketres.builderator.Renderer.BUILD_METHOD;
import static com.josketres.builderator.Renderer.getBuilderClassName;
import static java.lang.String.format;

@RunWith(Theories.class)
public class RendererTest {
    private static final int COMPILER_SUCCESS_CODE = 0;
    private static final String PARENT_BUILDER_CLASS = ParentBuilderClass.class.getName();
    private static final String PARENT_BUILDER_CLASS_OTHER_PACKAGE = ParentBuilderClassOtherPackage.class.getName();

    @Rule public JUnitSoftAssertions softly = new JUnitSoftAssertions();

    @Theory
    public void test_withParentClass_abstractClass(boolean otherPackage) throws IOException {
        test(true, otherPackage, false);
    }

    @Theory
    public void test_withParentClass_concreteClass(boolean otherPackage) throws IOException {
        test(true, otherPackage, true);
    }

    @Test
    public void test_withoutParentClass_abstractClass() throws IOException {
        test(false, false, false);
    }

    @Test
    public void test_withoutParentClass_concreteClass() throws IOException {
        test(false, false, true);
    }

    private void test(boolean withParentBuilderClass, boolean otherPackage, boolean concreteClass) throws IOException {
        MetadataExtractor metadataExtractor = new MetadataExtractor(NormalJavaBean.class);

        String parentBuilderClassName = null;
        String parentBuilderClassIfAny = otherPackage ? PARENT_BUILDER_CLASS_OTHER_PACKAGE : PARENT_BUILDER_CLASS;
        String extendsParentClause = " extends " + parentBuilderClassIfAny;
        if (withParentBuilderClass) {
            parentBuilderClassName = parentBuilderClassIfAny;
        }

        TargetClass targetClass = metadataExtractor.getMetadata();
        String source = new Renderer().render(targetClass, parentBuilderClassName, concreteClass);

        File root = File.createTempFile("java", null);
        root.delete();
        root.mkdirs();

        String packageDirs = targetClass.getPackageName().replace(".", System.getProperty("file.separator"));

        File packageFolder = new File(root, packageDirs);
        packageFolder.mkdirs();

        File sourceFile = new File(packageFolder,
                                   targetClass.getName().replace(".", System.getProperty("file.separator"))
                                   + "Builder.java");
        sourceFile.getParentFile().mkdirs();
        FileWriter fileWriter = null;
        try {
            fileWriter = new FileWriter(sourceFile);
            fileWriter.append(source);
        } finally {
            if (fileWriter != null) {
                fileWriter.close();
            }
        }

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        int result = compiler.run(null, System.out, System.err, sourceFile.getPath());
        softly.assertThat(result).isEqualTo(COMPILER_SUCCESS_CODE);

        String buildMethod = BUILD_METHOD + "()";
        String factoryMethod = Renderer.getFactoryMethod(targetClass) + "()";

        if (parentBuilderClassName == null) {
            softly.assertThat(source).doesNotContain(extendsParentClause);
        } else {
            softly.assertThat(source).contains(extendsParentClause);
        }

        if (concreteClass) {
            softly.assertThat(source).contains(buildMethod)
                  .contains(factoryMethod);
        } else {
            softly.assertThat(source).doesNotContain(buildMethod)
                  .doesNotContain(factoryMethod);
        }

        softly.assertThat(source)
              .contains(format("public class %s%s", getBuilderClassName(targetClass), concreteClass ? ' ' : '<'))
              .contains(format("protected %s(", getBuilderClassName(targetClass)));

    }
}
@@ -29,16 +29,51 @@
 rator;%0A%0A
+import com.google.common.io.Files;%0A
 import o
@@ -255,16 +255,56 @@
 Theory;%0A
+import org.junit.rules.TemporaryFolder;%0A
 import o
@@ -552,35 +552,8 @@
 le;%0A
-import java.io.FileWriter;%0A
 impo
@@ -1064,24 +1064,98 @@
 getName();%0A%0A
+    @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();%0A
     @Rule pu
@@ -1892,32 +1892,51 @@
 s IOException %7B%0A
+        // prepare%0A
         Metadata
@@ -2176,84 +2176,8 @@
 SS;%0A
-        String extendsParentClause = %22 extends %22 + parentBuilderClassIfAny;%0A
     
@@ -2274,33 +2274,32 @@
 fAny;%0A        %7D%0A
-%0A
         TargetCl
@@ -2348,16 +2348,33 @@
 adata();
+%0A%0A        // test
 %0A       
@@ -2478,1013 +2478,72 @@
     
-File root = File.createTempFile(%22java%22, null);%0A        root.delete();%0A        root.mkdirs();%0A%0A        String packageDirs = targetClass.getPackageName().replace(%22.%22, System.getProperty(%22file.separator%22));%0A%0A        File packageFolder = new File(root, packageDirs);%0A        packageFolder.mkdirs();%0A%0A        File sourceFile = new File(packageFolder,%0A                                   targetClass.getName().replace(%22.%22, System.getProperty(%22file.separator%22))%0A                                   + %22Builder.java%22);%0A        sourceFile.getParentFile().mkdirs();%0A        FileWriter fileWriter = null;%0A        try %7B%0A            fileWriter = new FileWriter(sourceFile);%0A            fileWriter.append(source);%0A        %7D finally %7B%0A            if (fileWriter != null) %7B%0A                fileWriter.close();%0A            %7D%0A        %7D%0A%0A        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();%0A        int result = compiler.run(null, System.out, System.err, sourceFile.getPath());%0A        softly.assertThat(result
+// verify%0A        softly.assertThat(compile(targetClass, source)
 ).is
@@ -2702,16 +2702,92 @@
  + %22()%22;
+%0A        String extendsParentClause = %22 extends %22 + parentBuilderClassIfAny;
 %0A%0A      
@@ -3507,16 +3507,500 @@
 ass)));%0A
-%0A
     %7D%0A
+%0A    private int compile(TargetClass targetClass, String source) throws IOException %7B%0A        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();%0A        File packageFolder = temporaryFolder.newFolder(targetClass.getPackageName().split(%22.%22));%0A        File sourceFile = new File(packageFolder, targetClass.getName() + %22Builder.java%22);%0A        Files.write(source.getBytes(), sourceFile);%0A%0A        return compiler.run(null, System.out, System.err, sourceFile.getPath());%0A    %7D%0A%0A
 %7D

Refactor RendererTest source code.