package fi.helsinki.cs.tmc.cli.core;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import fi.helsinki.cs.tmc.cli.Application;
import fi.helsinki.cs.tmc.cli.command.HelpCommand;
import fi.helsinki.cs.tmc.cli.io.TestIo;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class CommandFactoryTest {

    Application app;

    @Rule public ExpectedException exception = ExpectedException.none();

    private CliContext ctx;

    @Before
    public void setUp() {
        ctx = new CliContext(new TestIo());
        CommandFactory.reload();
    }

    @Test
    public void constructorAddsCommands() {
        assertTrue(!CommandFactory.getCommands().isEmpty());
    }

    @Test
    public void createHelpCommand() {
        assertNotNull(CommandFactory.createCommand("help"));
    }

    @Test
    public void createNonexistingCommand() {
        assertNull(CommandFactory.createCommand("foobar"));
    }

    @Command(name = "good", desc = "test")
    public static class GoodCommand extends AbstractCommand {

        @Override
        public void getOptions(Options options) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void run(CliContext context, CommandLine args) {
            throw new UnsupportedOperationException();
        }
    }

    @Test
    public void addGoodCommand() {
        CommandFactory.addCommand("category", GoodCommand.class);
        //TODO check the all the stuff in the command
        assertNotNull(CommandFactory.createCommand("good"));
    }

    public static class BadCommand extends AbstractCommand {

        @Override
        public void getOptions(Options options) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void run(CliContext context, CommandLine args) {
            throw new UnsupportedOperationException();
        }
    }

    @Test(expected = RuntimeException.class)
    public void addCommandWithoutProperAnnotation() {
        //WARNING The exception code leads to unpredicatble test results
        //exception.expect(RuntimeException.class);
        //exception.expectMessage(contains("annotation"));
        CommandFactory.addCommand("category", BadCommand.class);
    }

    private static class ReallyBadCommand {}

    @Test(expected = RuntimeException.class)
    public void addCommandThatDoesntExtendInterface() {
        //WARNING The exception code leads to unpredicatble test results
        //exception.expect(RuntimeException.class);
        //exception.expectMessage(contains("Interface"));
        CommandFactory.addCommand("category", ReallyBadCommand.class);
    }
}

@@ -588,16 +588,62 @@
 ption;%0A%0A
+import java.util.List;%0Aimport java.util.Set;%0A%0A
 public c
@@ -3014,11 +3014,1927 @@
 );%0A    %7D
+%0A%0A    @Test%0A    public void getCommandsGivesDefaultCommands() %7B%0A        assertNotSame(0, CommandFactory.getCommands().size());%0A        assertTrue(CommandFactory.getCommands().contains(%0A                CommandFactory.castToCommandClass(HelpCommand.class)));%0A    %7D%0A%0A    @Test%0A    public void getCommandsWhenSingleCommandIsAdded() %7B%0A        int oldSize = CommandFactory.getCommands().size();%0A        CommandFactory.addCommand(%22%22, GoodCommand.class);%0A        assertEquals(oldSize + 1, CommandFactory.getCommands().size());%0A        assertTrue(CommandFactory.getCommands().contains(%0A                CommandFactory.castToCommandClass(GoodCommand.class)));%0A    %7D%0A%0A    @Test%0A    public void getCategoryCommandsWhenItsEmpty() %7B%0A        assertEquals(null, CommandFactory.getCategoryCommands(%22xyz%22));%0A    %7D%0A%0A    @Test%0A    public void getCategoryCommandsWhenSingleCategorizedCommandIsAdded() %7B%0A        int oldSize = CommandFactory.getCommands().size();%0A        CommandFactory.addCommand(%22xyz%22, GoodCommand.class);%0A        List%3CClass%3CCommand%3E%3E list = CommandFactory.getCategoryCommands(%22xyz%22);%0A        assertEquals(1, list.size());%0A        assertEquals(GoodCommand.class, list.get(0));%0A    %7D%0A%0A    @Test%0A    public void getCommandCategoriesIsNotEmpty() %7B%0A        Set%3CString%3E list = CommandFactory.getCommandCategories();%0A        assertNotSame(0, list.size());%0A    %7D%0A%0A    @Test%0A    public void getCommandCategoriesContainsDefaultCategory() %7B%0A        Set%3CString%3E list = CommandFactory.getCommandCategories();%0A        assertTrue(list.contains(%22%22));%0A    %7D%0A%0A    @Test%0A    public void getCommandCategoriesContainsHiddenCategory() %7B%0A        Set%3CString%3E list = CommandFactory.getCommandCategories();%0A        assertTrue(list.contains(%22hidden%22));%0A    %7D%0A%0A    @Test%0A    public void getCommandCategoriesContainsAdminCategory() %7B%0A        Set%3CString%3E list = CommandFactory.getCommandCategories();%0A        assertTrue(list.contains(%22admin%22));%0A    %7D
 %0A%7D%0A

Add more unit tests for CommandFactory.