package picocli.spring;

import org.junit.After;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import picocli.CommandLine;
import picocli.CommandLine.IFactory;
import picocli.CommandLine.ParseResult;
import picocli.spring.boot.autoconfigure.sample.MyCommand;
import picocli.spring.boot.autoconfigure.sample.MySpringApp;

import java.util.Arrays;

import static org.junit.Assert.*;

public class PicocliSpringFactoryTest {

    private AnnotationConfigApplicationContext context;

    @After
    public void tearDown() {
        if (this.context != null) {
            this.context.close();
        }
    }

    @Test
    public void defaultPicocliSpringFactory() {
        load(MySpringApp.class);
        IFactory factory = this.context.getBean(IFactory.class);
        assertNotNull(factory);
        assertTrue(factory instanceof PicocliSpringFactory);
    }

    @Test
    public void testParseTopLevelCommand() {
        load(MySpringApp.class);
        IFactory factory = this.context.getBean(IFactory.class);
        MyCommand userObject = this.context.getBean(MyCommand.class);
        CommandLine cmd = new CommandLine(userObject, factory);
        cmd.parseArgs("-x", "abc", "xyz");
        assertEquals("abc", userObject.x);
        assertEquals(Arrays.asList("xyz"), userObject.positionals);
    }

    @Test
    public void testParseSubCommand() {
        load(MySpringApp.class);
        IFactory factory = this.context.getBean(IFactory.class);
        MyCommand userObject = this.context.getBean(MyCommand.class);
        CommandLine cmd = new CommandLine(userObject, factory);
        ParseResult parseResult = cmd.parseArgs("sub", "-y", "abc", "xyz");
        assertNull(userObject.x);
        assertNull(userObject.positionals);

        assertTrue(parseResult.hasSubcommand());
        MyCommand.Sub sub = (MyCommand.Sub) parseResult.subcommand().commandSpec().userObject();
        assertEquals("abc", sub.y);
        assertEquals(Arrays.asList("xyz"), sub.positionals);
    }

    @Test
    public void testParseSubSubCommand() {
        load(MySpringApp.class);
        IFactory factory = this.context.getBean(IFactory.class);
        MyCommand userObject = this.context.getBean(MyCommand.class);
        CommandLine cmd = new CommandLine(userObject, factory);
        ParseResult parseResult = cmd.parseArgs("sub", "subsub", "-z", "abc");
        assertNull(userObject.x);
        assertNull(userObject.positionals);

        assertTrue(parseResult.hasSubcommand());
        assertTrue(parseResult.subcommand().hasSubcommand());
        MyCommand.SubSub subsub = (MyCommand.SubSub) parseResult.subcommand().subcommand().commandSpec().userObject();
        assertEquals("abc", subsub.z);
        assertEquals("something", subsub.service.service());
    }

    private void load(Class<?> config, String... environment) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //EnvironmentTestUtils.addEnvironment(applicationContext, environment);
        applicationContext.register(config);
        applicationContext.refresh();
        this.context = applicationContext;
    }
}

@@ -373,16 +373,48 @@
 ngApp;%0A%0A
+import java.lang.reflect.Field;%0A
 import j
@@ -3243,11 +3243,2033 @@
 t;%0A    %7D
+%0A%0A    @Test(expected = NullPointerException.class)%0A    public void testConstructorNullAppContext() %7B%0A        new PicocliSpringFactory(null);%0A    %7D%0A%0A    @Test(expected = NullPointerException.class)%0A    public void testConstructorNullAppContextNullFallbackFactory() %7B%0A        new PicocliSpringFactory(null, null);%0A    %7D%0A%0A    @Test(expected = NullPointerException.class)%0A    public void testConstructorNullAppContextValidFallbackFactory() %7B%0A        new PicocliSpringFactory(null, CommandLine.defaultFactory());%0A    %7D%0A%0A    @Test(expected = NullPointerException.class)%0A    public void testConstructorValidAppContextNullFallbackFactory() %7B%0A        load(MySpringApp.class);%0A        new PicocliSpringFactory(context, null);%0A    %7D%0A%0A    @Test%0A    public void testConstructorAppContextUsesDefaultFactory() throws Exception %7B%0A        load(MySpringApp.class);%0A        PicocliSpringFactory factory = new PicocliSpringFactory(context);%0A        IFactory fallbackFactory = extractFallbackFactory(factory);%0A        assertNotNull(fallbackFactory);%0A        assertEquals(%22picocli.CommandLine$DefaultFactory%22, fallbackFactory.getClass().getName());%0A    %7D%0A%0A    @Test%0A    public void testConstructorAppContextFactoryUsesSpecifiedFactory() throws Exception %7B%0A        load(MySpringApp.class);%0A        IFactory myFactory = new IFactory() %7B%0A            @Override public %3CK%3E K create(Class%3CK%3E cls) %7Breturn null;%7D%0A        %7D;%0A        PicocliSpringFactory factory = new PicocliSpringFactory(context, myFactory);%0A        IFactory fallbackFactory = extractFallbackFactory(factory);%0A        assertNotNull(fallbackFactory);%0A        assertSame(myFactory, fallbackFactory);%0A    %7D%0A%0A    private IFactory extractFallbackFactory(PicocliSpringFactory factory) throws NoSuchFieldException, IllegalAccessException %7B%0A        Field fallbackFactoryField = PicocliSpringFactory.class.getDeclaredField(%22fallbackFactory%22);%0A        fallbackFactoryField.setAccessible(true);%0A        IFactory result = (IFactory) fallbackFactoryField.get(factory);%0A        return result;%0A    %7D
 %0A%7D%0A

add tests