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

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.contains;

import fi.helsinki.cs.tmc.cli.Application;
import fi.helsinki.cs.tmc.cli.command.core.Command;
import fi.helsinki.cs.tmc.cli.command.core.CommandFactory;
import fi.helsinki.cs.tmc.cli.command.core.CommandInterface;
import fi.helsinki.cs.tmc.cli.io.Io;
import fi.helsinki.cs.tmc.cli.io.TerminalIo;

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

public class CommandFactoryTest {

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

    CommandFactory factory;
    Application app;

    @Before
    public void setUp() {
        app = new Application(new TerminalIo());
        factory = app.getCommandFactory();
    }

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

    @Test
    public void createCommandWorksWithRealCommand() {
        assertNotNull(factory.createCommand(app, "help"));
    }

    @Test
    public void createCommandWorksWithBadCommand() {
        assertNull(factory.createCommand(app, "foobar"));
    }

    @Command(name = "good", desc = "test")
    public static class GoodCommand implements CommandInterface {
        public GoodCommand(Application app) {
            System.out.println("hello");
        }

        @Override
        public void run(String[] args, Io io) {
            throw new UnsupportedOperationException();
        }
    }

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

    public static class BadCommand implements CommandInterface {
        public BadCommand(Application app) {
            System.out.println("hello");
        }

        @Override
        public void run(String[] args, Io io) {
            throw new UnsupportedOperationException();
        }
    }

    @Test
    public void addCommandWithoutProperAnnotation() {
        exception.expect(RuntimeException.class);
        exception.expectMessage(contains("annotation"));
        factory.addCommand(BadCommand.class);
    }

    public static class ReallyBadCommand {
        public ReallyBadCommand(Application app) {
            System.out.println("hello");
        }
    }

    @Test
    public void addCommandThatDoesntExtendInterface() {
        exception.expect(RuntimeException.class);
        exception.expectMessage(contains("Interface"));
        factory.addCommand(ReallyBadCommand.class);
    }
}


@@ -2155,33 +2155,68 @@
     %7D%0A%0A    @Test
+(expected = RuntimeException.class)
 %0A
-
     public void 
@@ -2253,32 +2253,107 @@
 ion() %7B%0A        
+//WARNING The exception code leads to unpredicatble test results%0A        //
 exception.expect
@@ -2378,32 +2378,34 @@
 class);%0A        
+//
 exception.expect
@@ -2643,32 +2643,67 @@
     %7D%0A%0A    @Test
+(expected = RuntimeException.class)
 %0A    public void
@@ -2743,32 +2743,107 @@
 ace() %7B%0A        
+//WARNING The exception code leads to unpredicatble test results%0A        //
 exception.expect
@@ -2876,16 +2876,18 @@
         
+//
 exceptio

Disable exception message checking in factory tests.