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

import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import fi.helsinki.cs.tmc.cli.Application;
import fi.helsinki.cs.tmc.cli.io.TestIo;
import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir;
import fi.helsinki.cs.tmc.core.TmcCore;

import fi.helsinki.cs.tmc.core.domain.Course;
import fi.helsinki.cs.tmc.core.domain.Exercise;
import fi.helsinki.cs.tmc.core.domain.ProgressObserver;

import org.junit.Before;
import org.junit.Test;

import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

public class UpdateCommandTest {
    private Application app;
    private TestIo io;
    private TmcCore mockCore;
    private WorkDir workDir;


    @Before
    public void setUp() {
        io = new TestIo();
        app = new Application(io);
        mockCore = mock(TmcCore.class);
        app.setTmcCore(mockCore);
    }

    @Test
    public void failIfCoreIsNull() {
        app = spy(app);
        doReturn(null).when(app).getTmcCore();

        String[] args = {"update"};
        app.run(args);
        assertFalse(io.getPrint().contains("Not a course directory"));
    }

    @Test
    public void printsAnErrorMessageIfGivenCourseName() {
        String[] args = {"update", "course"};
        app.run(args);
        assertTrue(io.getPrint().contains("Use in the course directory"));
    }

    @Test
    public void printsAnErrorMessageIfUsedOutsideCourseDirectory() {
        workDir = new WorkDir(Paths.get(System.getProperty("java.io.tmpdir")));
        app.setWorkdir(workDir);
        String[] args = {"update"};
        app.run(args);
        assertTrue(io.getPrint().contains("Not a course directory"));
    }

    @Test
    public void worksRightIfAllExercisesAreUpToDate() {
        Callable<List<Exercise>> callableExercise = new Callable<List<Exercise>>() {
            @Override
            public List<Exercise> call() throws Exception {
                ArrayList<Exercise> tmp = new ArrayList<>();
                return tmp;
            }
        };

        when(mockCore.getExerciseUpdates(any(ProgressObserver.class), any(Course.class)))
                .thenReturn(callableExercise);

        String pathToDummycourse = UpdateCommandTest.class.getClassLoader()
                .getResource("dummy-courses/2016-aalto-c").getPath();

        workDir = new WorkDir(Paths.get(pathToDummycourse));
        app.setWorkdir(workDir);

        String[] args = {"update"};
        app.run(args);
        assertTrue(io.getPrint().contains("All exercises are up-to-date"));
    }

    @Test
    public void worksRightIfUpdatesAvailable() {
        Callable<List<Exercise>> callableExercise = new Callable<List<Exercise>>() {
            @Override
            public List<Exercise> call() throws Exception {
                ArrayList<Exercise> tmp = new ArrayList<>();
                tmp.add(new Exercise("exercise1"));
                tmp.add(new Exercise("exercise2"));
                return tmp;
            }
        };

        when(mockCore.getExerciseUpdates(any(ProgressObserver.class), any(Course.class)))
                .thenReturn(callableExercise);

        String pathToDummycourse = UpdateCommandTest.class.getClassLoader()
                .getResource("dummy-courses/2016-aalto-c").getPath();

        workDir = new WorkDir(Paths.get(pathToDummycourse));
        app.setWorkdir(workDir);

        String[] args = {"update"};
        app.run(args);
        assertTrue(io.getPrint().contains("Updates available for:"));
        assertTrue(io.getPrint().contains("exercise1"));
        assertTrue(io.getPrint().contains("exercise2"));
    }
}

@@ -125,24 +125,70 @@
 ssertFalse;%0A
+import static org.junit.Assert.assertNotNull;%0A
 import stati
@@ -749,14 +749,71 @@
 nit.
-Test;%0A
+BeforeClass;%0Aimport org.junit.Test;%0A%0Aimport java.nio.file.Path;
 %0Aimp
@@ -960,16 +960,116 @@
 dTest %7B%0A
+%0A    private static final String COURSE_NAME = %222016-aalto-c%22;%0A%0A    static Path pathToDummyCourse;%0A%0A
     priv
@@ -1172,16 +1172,286 @@
 rkDir;%0A%0A
+    @BeforeClass%0A    public static void setUpClass() throws Exception %7B%0A        pathToDummyCourse = Paths.get(SubmitCommandTest.class.getClassLoader()%0A                .getResource(%22dummy-courses/%22 + COURSE_NAME).toURI());%0A        assertNotNull(pathToDummyCourse);%0A    %7D%0A
 %0A    @Be
@@ -2917,155 +2917,8 @@
 );%0A%0A
-        String pathToDummycourse = UpdateCommandTest.class.getClassLoader()%0A                .getResource(%22dummy-courses/2016-aalto-c%22).getPath();%0A%0A
     
@@ -2939,34 +2939,24 @@
 new WorkDir(
-Paths.get(
 pathToDummyc
@@ -2950,32 +2950,31 @@
 (pathToDummy
-c
+C
 ourse)
-)
 ;%0A        ap
@@ -3726,155 +3726,8 @@
 );%0A%0A
-        String pathToDummycourse = UpdateCommandTest.class.getClassLoader()%0A                .getResource(%22dummy-courses/2016-aalto-c%22).getPath();%0A%0A
     
@@ -3752,26 +3752,16 @@
 WorkDir(
-Paths.get(
 pathToDu
@@ -3767,16 +3767,15 @@
 ummy
-c
+C
 ourse)
-)
 ;%0A  

Use uri instead of path