package info.javaspec.console;

import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParameterException;
import de.bechte.junit.runners.context.HierarchicalContextRunner;
import info.javaspec.console.MultiCommandParser.JCommanderParameters;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

import java.util.Arrays;
import java.util.Collections;

import static org.hamcrest.MatcherAssert.assertThat;

@RunWith(HierarchicalContextRunner.class)
public class MultiCommandParserTest {
  public class parseCommand {
    private MultiCommandParser subject;
    private Command mainCommand = Mockito.mock(Command.class);

    public class givenInvalidParametersForTheMainCommand {
      @Test(expected = ParameterException.class)
      public void throwsAnException() throws Exception {
        JCommanderParameters mainParamsWithNoOptions = () -> mainCommand;
        subject = new MultiCommandParser(mainParamsWithNoOptions);
        subject.parseCommand(Collections.singletonList("--unknown-option"));
      }
    }

    public class givenACommandWithInvalidParameters {
      @Test(expected = ParameterException.class)
      public void throwsAnException() throws Exception {
        JCommanderParameters mainParamsWithNoOptions = () -> mainCommand;
        subject = new MultiCommandParser(mainParamsWithNoOptions);
        subject.addCliCommand("valid-command", () -> Mockito.mock(Command.class));
        subject.parseCommand(Arrays.asList("valid-command", "--unknown-option"));
      }
    }

    public class givenOptionsMatchingTheMainCliCommand {
      @Before
      public void setup() throws Exception {
        JCommanderParameters mainParamsWithValidOption = new JCommanderParameters() {
          @Parameter(names = "--valid-option")
          public boolean validOption;

          @Override
          public Command toExecutableCommand() {
            return mainCommand;
          }
        };

        subject = new MultiCommandParser(mainParamsWithValidOption);
      }

      @Test
      public void parsesAllArgumentsAsMainArguments() throws Exception {
        Command returned = subject.parseCommand(Collections.singletonList("--valid-option"));
        assertThat(returned, Matchers.sameInstance(mainCommand));
      }
    }

    public class givenArgumentsMatchingACliCommand {
      private Command oneCommand = Mockito.mock(Command.class);

      @Before
      public void setup() throws Exception {
        JCommanderParameters main = () -> mainCommand;
        JCommanderParameters one = () -> oneCommand;
        subject = new MultiCommandParser(main);
        subject.addCliCommand("do-one-thing", one);
      }

      @Test
      public void parsesThatCommandAndItsArguments() throws Exception {
        Command returned = subject.parseCommand(Collections.singletonList("do-one-thing"));
        assertThat(returned, Matchers.sameInstance(oneCommand));
      }
    }
  }
}

@@ -1658,357 +1658,186 @@
     
-@Before%0A      public void setup() throws Exception %7B%0A        JCommanderParameters mainParamsWithValidOption = new JCommanderParameters() %7B%0A          @Parameter(names = %22--valid-option%22)%0A 
+private ParametersWithValidOption mainParameters;%0A%0A      @Before%0A
       
-   
 public 
-boolean validOption;%0A%0A          @Override%0A          public Command toExecutableCommand() %7B%0A            return mainCommand;%0A          %7D%0A        %7D;%0A
+void setup() throws Exception %7B%0A        mainParameters = new ParametersWithValidOption(mainCommand);
 %0A   
@@ -1883,32 +1883,21 @@
 ainParam
-sWithValidOption
+eters
 );%0A     
@@ -2137,32 +2137,104 @@
 (mainCommand));%0A
+        assertThat(mainParameters.validOption, Matchers.equalTo(true));%0A
       %7D%0A    %7D%0A%0A 
@@ -2884,11 +2884,416 @@
    %7D%0A  %7D
+%0A%0A  private static final class ParametersWithValidOption implements JCommanderParameters %7B%0A    private final Command command;%0A%0A    public ParametersWithValidOption(Command returningCommand) %7B%0A      this.command = returningCommand;%0A    %7D%0A%0A    @Parameter(names = %22--valid-option%22)%0A    public boolean validOption;%0A%0A    @Override%0A    public Command toExecutableCommand() %7B%0A      return this.command;%0A    %7D%0A  %7D
 %0A%7D%0A

Clarify and extract helpers