package org.leguan.language.gradle;

import com.google.common.io.Files;
import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.junit.Test;
import org.leguan.TestUtil;
import org.leguan.language.file.GenericFile;
import org.leguan.language.file.structured.AbstractStructuredFile;
import org.leguan.language.file.structured.ContentNodeHolder;
import org.leguan.language.file.structured.ContentNodeHolderContainer;
import org.leguan.language.file.structured.ContentNodeText;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;

public class GradleFileTest {

    @Test
    public void nonExistingFile () throws IOException {
        File tmpFile = new File (Files.createTempDir(), "something");
        GradleFile gradleFile = new GradleFile(new GenericFile(tmpFile));
        ContentNodeHolder contentNodeHolder = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("dependencies");
        contentNodeHolder.addTextNode("hello");
        gradleFile.save();
        String saved = FileUtils.readFileToString(tmpFile, Charset.defaultCharset());
        Assert.assertTrue ("Invalid content", saved.contains("dependencies"));
    }

    @Test
    public void addTextNodesNull() {
        GradleFile gradleFile = new GradleFile("");
        Assert.assertTrue(gradleFile.getContentNodeHolder().getSubnodes().isEmpty());
        gradleFile.getContentNodeHolder().addTextNodes((ContentNodeHolder) null);
        Assert.assertTrue(gradleFile.getContentNodeHolder().getSubnodes().isEmpty());
    }

    @Test
    public void createOrFindThisContentNodeHolder() {
        GradleFile gradleFile = new GradleFile("");
        ContentNodeHolder sameHolder = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("");
        Assert.assertEquals(gradleFile.getContentNodeHolder(), sameHolder);
    }

    @Test
    public void createOrFindSubClosureOnExistingSubClosure() {
        GradleFileStrategies gradleFileStrategies = new GradleFileStrategies();
        gradleFileStrategies.disableOrderingHolders();
        GradleFile gradleFile = new GradleFile(gradleFileStrategies);
        ContentNodeHolder contentNodeHolder = gradleFile.getContentNodeHolder();

        contentNodeHolder.addTextNode("//Hello");
        ContentNodeHolder allprojectsClosure = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("allprojects");
        ContentNodeHolder generatorClosure = allprojectsClosure.createOrFindContentNodeHolder("generator");
        generatorClosure.addTextNode("hallo");

        ContentNodeHolder closureAllProjects = contentNodeHolder.createOrFindContentNodeHolder("allprojects.generator.hans");
        Assert.assertEquals(" ", closureAllProjects.getGapNameAndBlock());
        closureAllProjects.addTextNode("something");

        ContentNodeHolder generatorHolder = contentNodeHolder.findContentNodeHolder("allprojects.generator");
        Assert.assertEquals("\n", generatorHolder.getSubnodes().get(0).toString());
        Assert.assertEquals("hallo", generatorHolder.getSubnodes().get(1).toString().trim());
        ContentNodeHolder hansHolder = generatorHolder.findContentNodeHolder("hans");
        Assert.assertEquals("\n", hansHolder.getSubnodes().get(0).toString());
        Assert.assertEquals("something", hansHolder.getSubnodes().get(1).toString().trim());
    }

    @Test
    public void createOrFindSubClosure() {
        GradleFile gradleFile = new GradleFile(new GradleFileStrategies());
        ContentNodeHolder contentNodeHolder = gradleFile.getContentNodeHolder();

        contentNodeHolder.addTextNode("//Hello");
        ContentNodeHolder closureAllProjects = contentNodeHolder.createOrFindContentNodeHolder("allprojects.generator.hans");
        closureAllProjects.addTextNode("something");

        System.out.println(contentNodeHolder.toString());

        ContentNodeHolder generatorHolder = contentNodeHolder.findContentNodeHolder("allprojects.generator");
        Assert.assertEquals("\n", generatorHolder.getSubnodes().get(0).toString());
        ContentNodeHolder hansHolder = generatorHolder.findContentNodeHolder("hans");
        Assert.assertEquals("\n", hansHolder.getSubnodes().get(0).toString());
        Assert.assertEquals("something", hansHolder.getSubnodes().get(1).toString().trim());
    }


    @Test
    public void addNewClosure() {

        GradleFile gradleFile = new GradleFile();
        ContentNodeHolder contentNodeHolder = gradleFile.getContentNodeHolder();

        contentNodeHolder.addTextNode("//Hello");
        ContentNodeHolder closureAllProjects = contentNodeHolder.createOrFindContentNodeHolder("allprojects");
        closureAllProjects.addTextNode("something");

        ContentNodeHolder subproject = contentNodeHolder.createOrFindContentNodeHolder("subproject (':project1')");
        subproject.addTextNode("something2");

        String[] texts = contentNodeHolder.toString().split("\n");
        System.out.println(contentNodeHolder.getContent());
        Assert.assertEquals("//Hello", texts[0]);
        Assert.assertEquals("allprojects {", texts[1]);
        Assert.assertEquals("  something", texts[2]);
        Assert.assertEquals("}", texts[3]);
        Assert.assertEquals("subproject (':project1') {", texts[4]);
        Assert.assertEquals("  something2", texts[5]);
        Assert.assertEquals("}", texts[6]);
    }

    @Test
    public void addToExistingClosure() {

        GradleFile gradleFile = new GradleFile();
        ContentNodeHolder contentNodeHolder = gradleFile.getContentNodeHolder();
        contentNodeHolder.addTextNode("//Hello");
        ContentNodeHolder closureAllProjects = contentNodeHolder.createOrFindContentNodeHolder("allprojects");
        closureAllProjects.addTextNode("something");

        closureAllProjects = contentNodeHolder.createOrFindContentNodeHolder("allprojects");
        closureAllProjects.addTextNode("something2");

        String[] texts = contentNodeHolder.toString().split("\n");

        Assert.assertEquals("//Hello", texts[0]);
        Assert.assertEquals("allprojects {", texts[1]);
        Assert.assertEquals("  something", texts[2]);
        Assert.assertEquals("  something2", texts[3]);
        Assert.assertEquals("}", texts[4]);
    }


    @Test
    public void applySpecialLines() {
        GradleFile writer = new GradleFile();
        ContentNodeHolder apply = writer.getContentNodeHolder().createOrFindContentNodeHolder("apply");
        apply.addTextNode("}");
        apply.addTextNode("{");
        apply.addTextNode("      ");
        Assert.assertEquals("Number of applied plugins invalid (not applied once) $apply.directContent", 3, apply.getSubnodes().size());
    }

    @Test
    public void excludeEmptyClosure() {
        GradleFile writer = new GradleFile();

        ContentNodeHolder extensionFullHolder = writer.getContentNodeHolder().createOrFindContentNodeHolder("extensionFull");
        ContentNodeHolder extensionEmptyHolder = writer.getContentNodeHolder().createOrFindContentNodeHolder("extensionEmpty");
        ContentNodeHolder extensionNullHolder = writer.getContentNodeHolder().createOrFindContentNodeHolder("extensionNull");
        extensionFullHolder.addTextNodes(Arrays.asList("line1", "line2"));
        extensionEmptyHolder.addTextNodes(Arrays.asList());
        extensionNullHolder.addTextNodes((Collection<String>) null);

        Assert.assertTrue("Full extension should be written:" + writer, writer.toString().contains("extensionFull"));
        Assert.assertFalse("Empty extension should not be written:" + writer, writer.toString().contains("extensionEmpty"));
        Assert.assertFalse("Null should not be written:" + writer, writer.toString().contains("extensionNull"));
    }

    @Test
    public void copyContentNodeHolder() {
        Collection<String> content = Arrays.asList("buildscript {",
            "  repositories {",
            "    mavenLocal()",
            "  }",
            "  dependencies {",
            "    classpath 'bla:bla:0.1'",
            "  }",
            "}",
            "");
        GradleFile gradleFile1 = new GradleFile(String.join("\n", content));
        ContentNodeHolder buildscriptHolder = gradleFile1.findContentNodeHolder("buildscript");

        GradleFile gradleFile2 = new GradleFile();

        ContentNodeHolder buildscriptTargetHolder = gradleFile2.getContentNodeHolder().createOrFindContentNodeHolder("buildscript");
        buildscriptTargetHolder.addTextNodes(buildscriptHolder);

        ContentNodeHolder allprojectsTargetHolder = gradleFile2.getContentNodeHolder().createOrFindContentNodeHolder("allprojects");
        allprojectsTargetHolder.addTextNode("hello");

        System.out.println(gradleFile2.getContentNodeHolder().getContent().toString());
        System.out.println(gradleFile2.toString());

        List<String> lines = Arrays.asList(gradleFile2.toString().split("\n"));

        Assert.assertEquals("buildscript {", lines.get(0));
        Assert.assertEquals("  repositories {", lines.get(2));
        Assert.assertEquals("    mavenLocal()", lines.get(3));
        Assert.assertEquals("  }", lines.get(4));
        Assert.assertEquals("  dependencies {", lines.get(5));
        Assert.assertEquals("    classpath 'bla:bla:0.1'", lines.get(6));
        Assert.assertEquals("  }", lines.get(7));
        Assert.assertEquals("}", lines.get(8));
        Assert.assertEquals("allprojects {", lines.get(9));
        Assert.assertEquals("  hello", lines.get(10));
        Assert.assertEquals("}", lines.get(11));
    }

    @Test
    public void createOrFindContentNodeHolderOnSub() {
        final String buildscriptBlockName = "buildscript";
        GradleFile gradleFile = new GradleFile();
        ContentNodeHolder allProjectsHolder = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("allprojects");
        ContentNodeHolder subProjectsHolder = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("subprojects");
        subProjectsHolder.addTextNode("hallo");


        Assert.assertNull("blockname available per default", allProjectsHolder.findContentNodeHolder(buildscriptBlockName));
        int numberOfBlocks = allProjectsHolder.getSubnodes().size();
        ContentNodeHolder buildScriptHolder = allProjectsHolder.createOrFindContentNodeHolder(buildscriptBlockName);
        buildScriptHolder.addTextNode("dummy");

        int numberOfBlocksAfter = allProjectsHolder.getSubnodes().size();

        System.out.println(gradleFile);


        Assert.assertEquals("Number of blocks not increased", numberOfBlocks + 1, numberOfBlocksAfter);
        Assert.assertNotNull("blockname not available after lazy adding", allProjectsHolder.findContentNodeHolder(buildscriptBlockName));

        allProjectsHolder.createOrFindContentNodeHolder(buildscriptBlockName);
        int numberOfBlocksAfterSecond = allProjectsHolder.getSubnodes().size();
        Assert.assertEquals("Number of blocks increased for existing block", numberOfBlocksAfterSecond, numberOfBlocksAfter);

        List<String> lines = Arrays.asList(gradleFile.toString().split("\n"));

        System.out.println(gradleFile);

        Assert.assertEquals("allprojects {", lines.get(0));
        Assert.assertEquals("  buildscript {", lines.get(1));
        Assert.assertEquals("    dummy", lines.get(2));
        Assert.assertEquals("  }", lines.get(3));
        Assert.assertEquals("}", lines.get(4));
        Assert.assertEquals("subprojects {", lines.get(5));
        Assert.assertEquals("  hallo", lines.get(6));
        Assert.assertEquals("}", lines.get(7));
    }

    @Test
    public void createOrFindContentNodeHolderOnRoot() {
        final String buildscriptBlockName = "buildscript";
        GradleFile gradleFile = new GradleFile("");
        Assert.assertNull("blockname available per default", gradleFile.findContentNodeHolder(buildscriptBlockName));
        int numberOfBlocks = gradleFile.getContentNodeHolder().getSubnodes().size();
        gradleFile.getContentNodeHolder().createOrFindContentNodeHolder(buildscriptBlockName);
        int numberOfBlocksAfter = gradleFile.getContentNodeHolder().getSubnodes().size();
        System.out.println(gradleFile.toString());

        Assert.assertEquals("Number of blocks not increased", numberOfBlocks + 1, numberOfBlocksAfter);
        Assert.assertNotNull("blockname not available after lazy adding", gradleFile.findContentNodeHolder(buildscriptBlockName));

        gradleFile.getContentNodeHolder().createOrFindContentNodeHolder(buildscriptBlockName);
        int numberOfBlocksAfterSecond = gradleFile.getContentNodeHolder().getSubnodes().size();
        Assert.assertEquals("Number of blocks increased for existing block", numberOfBlocksAfterSecond, numberOfBlocksAfter);
    }

    @Test
    public void addTextNodesFromDifferentContentHolder() {
        GradleFile gradleFile = new GradleFile();
        ContentNodeHolder holder = new ContentNodeHolder(gradleFile, null, "{", "}", "\n", "hans");
        holder.setIndention("  ");
        holder.addTextNodes(Arrays.asList("line3", "line4"));


        ContentNodeHolder holder2 = new ContentNodeHolder(gradleFile, null, "{", "}", "\n", "hans");
        holder2.setIndention("  ");
        holder2.addTextNodes(Arrays.asList("line1", "line2"));
        holder2.addTextNodes(holder);

        Assert.assertEquals("line1", holder2.getDirectContent().get(0).trim());
        Assert.assertEquals("line2", holder2.getDirectContent().get(1).trim());
        Assert.assertEquals("line3", holder2.getDirectContent().get(2).trim());
        Assert.assertEquals("line4", holder2.getDirectContent().get(3).trim());
    }

    @Test
    public void getContent() {
        Collection<String> content = Arrays.asList("buildscript {",
            "  repositories {",
            "    mavenLocal()",
            "  }",
            "  dependencies {",
            "    classpath 'bla:bla:0.1'",
            "  }",
            "}",
            "");
        GradleFile gradleFile = new GradleFile(String.join("\n", content));
        ContentNodeHolder contentNodeHolder = gradleFile.getContentNodeHolder().findContentNodeHolder("buildscript");
        ContentNodeHolder contentNodeHolderTarget = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("buildscriptTarget");
        List<String> contentAsList = contentNodeHolder.getContent();

        String contentAsLog = contentAsList.toString().replace(",", "\n");
        Assert.assertEquals("Content1 in " + contentAsLog, "repositories {", contentAsList.get(0).trim());
        Assert.assertEquals("Content2 in " + contentAsLog, "mavenLocal()", contentAsList.get(1).trim());
        Assert.assertEquals("Content3 in " + contentAsLog, "}", contentAsList.get(2).trim());
        Assert.assertEquals("Content4 in " + contentAsLog, "dependencies {", contentAsList.get(3).trim());
        Assert.assertEquals("Content5 in " + contentAsLog, "classpath 'bla:bla:0.1'", contentAsList.get(4).trim());
        Assert.assertEquals("Content6 in " + contentAsLog, "}", contentAsList.get(5).trim());
        Assert.assertEquals("Number of content lines invalid", 6, contentAsList.size());

        contentNodeHolderTarget.addTextNodes(contentNodeHolder.getContent());
        List<String> contentTargetAsList = contentNodeHolderTarget.getContent();

        String contentTargetAsLog = contentTargetAsList.toString().replace(",", "\n");
        Assert.assertEquals("Content1 in " + contentTargetAsLog, "repositories {", contentTargetAsList.get(0).trim());
        Assert.assertEquals("Content2 in " + contentTargetAsLog, "mavenLocal()", contentTargetAsList.get(1).trim());
        Assert.assertEquals("Content3 in " + contentTargetAsLog, "}", contentTargetAsList.get(2).trim());
        Assert.assertEquals("Content4 in " + contentTargetAsLog, "dependencies {", contentTargetAsList.get(3).trim());
        Assert.assertEquals("Content5 in " + contentTargetAsLog, "classpath 'bla:bla:0.1'", contentTargetAsList.get(4).trim());
        Assert.assertEquals("Content6 in " + contentTargetAsLog, "}", contentTargetAsList.get(5).trim());
        Assert.assertEquals("Number of content lines invalid", 6, contentTargetAsList.size());
    }

    @Test
    public void getDirectContentFromRecursive() {
        GradleFile gradleFile = new GradleFile();
        ContentNodeHolder holder = gradleFile.getContentNodeHolder();
        holder.addTextNode("hallo");
        ContentNodeHolder holder1 = holder.createOrFindContentNodeHolder("buildscript");
        holder1.addTextNode("zeuchs");
        ContentNodeHolder holderRepo = holder1.createOrFindContentNodeHolder("repository");
        holderRepo.addTextNode("xxxx");

        Assert.assertTrue(holder.getDirectContent().toString() + " does not contain direct content hallo", holder.getDirectContent().toString().contains("hallo"));
        Assert.assertTrue(holder1.getDirectContent().toString() + " does not contain direct content zeuchs", holder1.getDirectContent().toString().contains("zeuchs"));

        Assert.assertTrue(holderRepo.getDirectContent().toString() + " does not contain direct xxxx", holderRepo.getDirectContent().toString().contains("xxxx"));
    }

    @Test
    public void replaceNotTextNotExisting() {
        GradleFile gradleFile = new GradleFile();

        ContentNodeHolder closureAllProjects = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("allprojects");

        closureAllProjects.addTextNode("hans = alt");
        closureAllProjects.addTextNode("doedel = jung");
        closureAllProjects.addOrReplaceGenericText(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("srcDir");
            }
        }, "srcDir = was neues");
        String text = gradleFile.toString();

        List<String> lines = Arrays.asList(gradleFile.toString().split("\n"));

        Assert.assertEquals(gradleFile.toString(), "allprojects {", lines.get(0));
        Assert.assertEquals(gradleFile.toString(), "  hans = alt", lines.get(1));
        Assert.assertEquals(gradleFile.toString(), "  doedel = jung", lines.get(2));
        Assert.assertEquals(gradleFile.toString(), "  srcDir = was neues", lines.get(3));
        Assert.assertEquals(gradleFile.toString(), "}", lines.get(4));
    }

    private File submodule = TestUtil.getSubProject("leguan-languages/leguan-language-file");
    private File rootpath = new File (submodule, "src/test/resources/gradlefile");


    @Test
    public void orderingRootClosures () {
        GradleFile gradleFile = new GradleFile();
        ContentNodeHolder contentNodeHolderAllprojects = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("allprojects");
        contentNodeHolderAllprojects.addTextNode("allprojects");
        ContentNodeHolder contentNodeHolderSubprojects = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("subprojects");
        contentNodeHolderSubprojects.addTextNode("subprojects");
        ContentNodeHolder contentNodeHolderDependencyManagement = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("dependencyManagement");
        contentNodeHolderDependencyManagement.addTextNode("dependencyManagement");
        ContentNodeHolder contentNodeHolderBuildscript = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("buildscript");
        contentNodeHolderBuildscript.addTextNode("buildscript");

        System.out.println (gradleFile.toString());

    }

    @Test
    public void ordering () {
        GradleFile gradleFile = new GradleFile();
        gradleFile.getGradleFileStrategies().setOrderedHolders(null);
        ContentNodeHolder allprojects = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("allprojects");
        allprojects.addTextNode("inAllpojects");
        ContentNodeHolder contentNodeHolder = gradleFile.getContentNodeHolder();
        contentNodeHolder.getSubnodes().add(0, new ContentNodeText(gradleFile, contentNodeHolder, "preAllprojects", "\n"));
        System.out.println (gradleFile.toString());

    }


    @Test
    public void emptyClosureWithoutOptimizing () {
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/emptyClosure.gradle");

        GradleFileStrategies configuration = new GradleFileStrategies();
        configuration.setOptimizeEmptyClosures(false);
        GradleFile gradleFile = new GradleFile(configuration, new GenericFile(file));
        String content = gradleFile.toString();
        System.out.println (content);
        Assert.assertTrue ("Empty sub as method call must exist on optimizing ", content.contains("    emptySubAsMethodCall ()"));
        Assert.assertTrue ("Non empty closure must exist on optimizing ", content.contains("    nonEmptyOneLineClosure {println 'Hello'}"));
        Assert.assertTrue ("Multi line empty closure must exist on optimizing ", content.contains("    emptySubClosure2 {"));
        Assert.assertTrue ("Single line empty closure must exist on optimizing ", content.contains("    emptySubClosure {}"));
    }

    @Test
    public void emptyClosureWithOptimizing () {
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/emptyClosure.gradle");

        GradleFile gradleFile = new GradleFile(new GenericFile(file));
        String content = gradleFile.toString();
        System.out.println (content);
        Assert.assertTrue ("Empty sub as method call must exist on optimizing ", content.contains("emptySubAsMethodCall ()"));
        Assert.assertTrue ("Non empty closure must exist on optimizing ", content.contains("nonEmptyOneLineClosure {println 'Hello'}"));
        Assert.assertFalse ("Multi line empty closure must not exist on optimizing ", content.contains("emptySubClosure2"));
        Assert.assertFalse ("Multi line empty closure must exist on optimizing ", content.contains("emptySubClosure"));
    }

    @Test
    public void invalidString () {
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/invalidString.gradle");

        GradleFile gradleFile = new GradleFile(new GenericFile(file));
        System.out.println (gradleFile.toString());
        Assert.assertNotNull ("someclosure not found", gradleFile.getContentNodeHolder().findContentNodeHolder("someclosure"));

    }


    @Test
    public void dotDotSlashFile () {
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/dotdotSlashFile.gradle");

        GradleFile gradleFile = new GradleFile(new GenericFile(file));
        System.out.println (gradleFile.toString());
        Assert.assertNotNull ("buildscript.dependencies not found", gradleFile.getContentNodeHolder().findContentNodeHolder("buildscript.dependencies"));




    }
    @Test
    public void readAndWrite () {
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/readAndSerialize.gradle");

        GradleFile gradleFile = new GradleFile(new GenericFile(file));
        Assert.assertFalse(gradleFile.toString().contains("}}"));
        System.out.println (gradleFile.toString());


    }


    @Test
    public void property () throws IOException {
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/variable.gradle");
        String line = "println \"Version <${project.rootProject.name}_${project.rootProject.version}>\"";

        GradleFile gradleFile = new GradleFile(new GenericFile(file));

        Collection<String> content = Arrays.asList(gradleFile.toString().split("\n"));
        Assert.assertTrue ("Line " + line + " not contained in content" +  String.join("\n", content), content.contains(line));
    }


    @Test
    public void commentedClosure () {
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/comment.gradle");
        GradleFile gradleFile = new GradleFile(new GenericFile(file));
        ContentNodeHolder holderContainer = gradleFile.getContentNodeHolder();
        ContentNodeHolder buildscript = holderContainer.findContentNodeHolder("buildscript");
        ContentNodeHolder dependencyManagement = holderContainer.findContentNodeHolder("allprojects.dependencyManagement");
        Assert.assertTrue ("Multiline commented code must be parsed as normal token", buildscript.findContentHolderNodes().isEmpty());
        Assert.assertTrue ("Oneline commented code must be parsed as normal token", dependencyManagement.findContentHolderNodes().isEmpty());
    }

    @Test
    public void namedClosures () {
        final String CLOSURE_NAME = "junit";
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/namedClosures.gradle");
        GradleFile gradleFile = new GradleFile(new GenericFile(file));
        ContentNodeHolderContainer holderContainer = gradleFile.getContentNodeHolder().createNodeHolderContainer();

        ContentNodeHolder junitHolder = holderContainer.filterByName(CLOSURE_NAME).getSingleItem();
        ContentNodeHolder antHolder = junitHolder.findContentHolderNodes().get(0);
        Assert.assertEquals ("ant.copy(toDir: 'build/resources/test/xml')", antHolder.getName());
    }

    @Test
    public void readFromString () {
        GradleFile gradleFile = new GradleFile("\nbuildscript {\n" +
            "  dependencies {\n" +
            "    classpath 'de.leguan.gradle:nprod_gradleplugins:3_41'\n" +
            "  }\n" +
            "\n" +
            "}");
        ContentNodeHolder dependencies = gradleFile.getContentNodeHolder().findContentNodeHolder("buildscript.dependencies");
        Assert.assertNotNull ("buildscript.dependencies not found", dependencies);

    }

    @Test
    public void findBuildscriptDependencies () {
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/findBuildscriptDependencies.gradle");

        GradleFile gradleFile = new GradleFile(new GenericFile(file));
        ContentNodeHolder buildscriptDependenciesHolder = gradleFile.getContentNodeHolder().findContentNodeHolder("buildscript.dependencies");
        System.out.println(buildscriptDependenciesHolder.getContent());

    }
    @Test
    public void readClass () {
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/withClass.gradle");

        new GradleFile(new GenericFile(file.getParentFile(), file));
    }

    @Test
    public void withQuotationMarks () {
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/withQuotationMarks.gradle");
        GradleFile gradleFile = new GradleFile(new GenericFile(file));
        Assert.assertNotNull (gradleFile.getContentNodeHolder().findContentNodeHolder("buildscript"));
        ContentNodeHolder buildDependenciesHolder = gradleFile.getContentNodeHolder().findContentNodeHolder("buildscript.dependencies");
        Assert.assertNotNull (gradleFile.getContentNodeHolder().findContentNodeHolder("apply"));
        Assert.assertNotNull (gradleFile.getContentNodeHolder().findContentNodeHolder("dependencies"));
        System.out.println ("content: " + buildDependenciesHolder.getContent());
        System.out.println ("toString:" + buildDependenciesHolder.toString());
        Assert.assertEquals ("classpath \"group:name:$gradlepluginsSnapshot\"", buildDependenciesHolder.getContent().get(0).trim());

    }

    @Test
    public void sortExtensions () {
        GradleFile gradleFile = new GradleFile();
        ContentNodeHolder workflowHolder = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("custom");
        workflowHolder.addTextNodes(Arrays.asList("Hans", "Dampf"));

        ContentNodeHolder applyHolder = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("apply");
        applyHolder.addTextNodes(Arrays.asList("plugin: 'hans'", "plugin: 'gerch'"));


        ContentNodeHolder buildscriptHolder = gradleFile.getContentNodeHolder().createOrFindContentNodeHolder("buildscript");
        buildscriptHolder.addTextNodes(Arrays.asList("repo", "bla"));

        String buildFile = gradleFile.toString();

        int indexOfCustom = buildFile.indexOf("custom");
        int indexOfBuildscript = buildFile.indexOf("buildscript");
        int indexOfApply = buildFile.indexOf("apply");

        Assert.assertTrue ("Order not correct" +  indexOfBuildscript+"-" + indexOfApply + "-" + indexOfCustom + ") " + buildFile,
            indexOfBuildscript < indexOfApply && indexOfApply < indexOfCustom);
    }


    @Test
    public void readExtensions () {
        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/extensions.gradle");

        GradleFile visitor = new GradleFile(new GenericFile(file));

        ContentNodeHolder extension = visitor.findContentNodeHolder("plugin1");
        Assert.assertEquals("plugin1", extension.getName());
        Assert.assertEquals (1, extension.getDirectContent().size());
        Assert.assertEquals ("prefixGen false", extension.getDirectContent().get(0).trim());

        Assert.assertNull(visitor.getContentNodeHolder().findContentNodeHolder("plugin3"));
    }

    @Test
    public void appliedPlugins() {
        String scriptContents = "apply {\n" +
            "plugin 'layout'\n" +
            "plugin 'bla'\n" +
            "plugin 'castor'\n" +
            "plugin 'jasperReports'\n" +
            "otherthing 'tests.gradle'\n" +
            "}";

        GradleFile visitor = new GradleFile(scriptContents);
        Collection<String> plugins = visitor.getAppliedPlugins();
        Assert.assertEquals("Wrong number of plugins found $plugins", 4, plugins.size());
        Assert.assertTrue(plugins.contains("bla"));
        Assert.assertTrue(plugins.contains("castor"));
        Assert.assertFalse(plugins.contains("other"));
    }


    @Test
    public void appliedPluginsNoneDefined ( ){
        String scriptContents = "something {}";

        GradleFile visitor = new GradleFile(scriptContents);
        Collection<String> plugins = visitor.getAppliedPlugins();
        Assert.assertEquals ("Wrong number of plugins found $plugins", 0, plugins.size());
    }


    @Test
    public void applyPluginOnce () {
        GradleFile writer = new GradleFile();
        ContentNodeHolder apply = writer.getContentNodeHolder().createOrFindContentNodeHolder("apply");
        apply.addTextNode("plugin 'bla'");
        apply.addTextNode("plugin 'bla'");
        Assert.assertEquals ("Number of applied plugins invalid (not applied once)", 1, apply.getDirectContent().size());

    }

    @Test
    public void addRootText () {
        GradleFile gradleFile = new GradleFile();
        gradleFile.getContentNodeHolder().addTextNode("hello");
        Assert.assertEquals ("hello\n", gradleFile.toString());
    }

    @Test
    public void readExample () {
        String content = "jaxb {\n   include('/**/gen/*.xsd')\n   appendXsdName = true\n   prefixGen = true\n   }\n  ";
        new GradleFile(content);
    }

    @Test
    public void readOneLiner () {
        GradleFile gradleFile = new GradleFile("Hello");
        Assert.assertEquals ("Hello", gradleFile.toString());
    }

    @Test
    public void readContent () {
        String content = "buildscript {\n" +
            "  repositories {\n" +
            "    maven { url 'http://mavenrepo' }\n" +
            "    ivy { url 'http://ivy' }\n" +
            "    mavenLocal()\n" +
            "  }\n" +
            "  dependencies {\n" +
            "    classpath 'org.apache:commons:3.5'\n" +
            "    classpath 'anygroup:anyname:6.33'\n" +
            "  }\n" +
            "}\n" +
            "apply {\n"+
            "  plugin 'plugin1'\n" +
            "  plugin 'plugin2'\n" +
            "}\n";

        System.out.println ("before:\n" + content);

        File file = TestUtil.getPath("leguan-languages/leguan-language-file", "src/test/resources/gradlefile/content.gradle");
        GradleFile gradleFile = new GradleFile(new GenericFile(file));

        Assert.assertEquals ("Content differs: " + content + " <-> " + gradleFile.getContentNodeHolder().toString(),  content, gradleFile.getContentNodeHolder().toString());


        ContentNodeHolder buildscriptHolder = gradleFile.getContentNodeHolder().findContentNodeHolder("buildscript");
        Assert.assertNotNull ("buildscript not found", buildscriptHolder);
        ContentNodeHolder applyHolder = gradleFile.getContentNodeHolder().findContentNodeHolder("apply");
        Assert.assertNotNull ("apply not found", applyHolder);

        ContentNodeHolder repositoriesHolder = gradleFile.getContentNodeHolder().findContentNodeHolder("buildscript.repositories");
        Assert.assertNotNull ("buildscript.repositories not found", repositoriesHolder);
        ContentNodeHolder dependenciesHolder = gradleFile.getContentNodeHolder().findContentNodeHolder("buildscript.dependencies");
        Assert.assertNotNull ("buildscript.dependencies not found", dependenciesHolder);

        ContentNodeHolder mavenHolder = gradleFile.getContentNodeHolder().findContentNodeHolder("buildscript.repositories.maven");
        Assert.assertNotNull ("buildscript.repositories.maven not found", mavenHolder);
        ContentNodeHolder ivyHolder = gradleFile.getContentNodeHolder().findContentNodeHolder("buildscript.repositories.ivy");
        Assert.assertNotNull ("buildscript.repositories.ivy not found", ivyHolder);

        Assert.assertNotNull ("mavenLocal text node not found", repositoriesHolder.findContentNodeText(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("mavenLocal()");
            }
        }));


    }
    @Test
    public void getAppliedPlugins () {
        String content =  "apply {\n" +
            "    plugin 'io.spring.dependency-management'\n" +
            "    from 'tests.gradle'\n" +
            "";
        System.out.println (content);
        GradleFile gradleFile = new GradleFile(content);
        List<String> appliedPlugins = gradleFile.getAppliedPlugins();
        Assert.assertEquals (1, appliedPlugins.size());
        Assert.assertEquals ("io.spring.dependency-management", appliedPlugins.get(0));

    }

    @Test
    public void readBuildGradleDirectConentFromMemoryNested () {
        String content =  "hello {\n" +
            "   second {\n" +
            "     bla\n" +
            "   } \n" +
            "   inHello\n" +
            "}";
        GradleFile gradleFile = new GradleFile(content);

        ContentNodeHolder contentNode = gradleFile.getContentNodeHolder().findContentNodeHolder("hello");
        Collection<String> directContent = contentNode.getDirectContent();
        System.out.println ("\nDirect: " + directContent);
        Assert.assertTrue (directContent.iterator().next().contains("inHello"));

    }

    @Test
    public void readBuildGradleDirectConentFromMemory () {
        String content =  "hello {\n" +
            "   bla\n" +
            "  \n" +
            "   inHello\n" +
            "}";
        GradleFile gradleFile = new GradleFile(content);

        ContentNodeHolder contentNode = gradleFile.getContentNodeHolder().findContentNodeHolder("hello");
        List<String> directContent = contentNode.getDirectContent();
        Assert.assertEquals (directContent.toString() + "-" + directContent.get(0), "bla", directContent.get(0).trim());
        Assert.assertEquals (directContent.get(1), "", directContent.get(1).trim());
        Assert.assertEquals (directContent.get(2), "inHello", directContent.get(2).trim());

    }

    @Test
    public void readBuildGradle () throws IOException {
        File buildGradle = new File (rootpath, "build.gradle");
        String originalContent = FileUtils.readFileToString(buildGradle, Charset.defaultCharset());
        GradleFile gradleFile = new GradleFile(new GenericFile(buildGradle));

        ContentNodeHolder root = gradleFile.getContentNodeHolder();

        ContentNodeHolder buildscriptNode = root.findContentNodeHolder("buildscript");
        ContentNodeHolder repositoriesNode = root.findContentNodeHolder("buildscript.repositories");

        Assert.assertEquals ("buildscript diffs", "buildscript", buildscriptNode.getName());
        Assert.assertEquals ("repositories diffs", "repositories", repositoriesNode.getName());

        Assert.assertEquals ("Reserialized diffs from origin content", originalContent, gradleFile.toString());
    }

    @Test
    public void findBlock ()  {
        File buildGradle = new File (rootpath, "build.gradle");
        AbstractStructuredFile structuredFile = new GradleFile(new GenericFile(buildGradle));
        ContentNodeHolder holder = structuredFile.getContentNodeHolder().findContentNodeHolder("buildscript.repositories.ivy");
        Assert.assertNotNull ("Holder not found", holder);
    }

    @Test
    public void springDependenciesActivated () throws IOException {
        File buildGradle = new File (rootpath, "springDependenciesActivated.gradle");
        GradleFile gradleFile = new GradleFile(new GenericFile(buildGradle));
        Assert.assertNotNull ("Spring dep plugin not used", gradleFile.getSpringDependencyManagement());
    }

    @Test
    public void springDependenciesNotActivated () throws IOException {
        File buildGradle = new File (rootpath, "build.gradle");
        GradleFile gradleFile = new GradleFile(new GenericFile(buildGradle));
        Assert.assertNull ("Spring dep plugin used", gradleFile.getSpringDependencyManagement());
    }


}
