/*******************************************************************************
 * (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License v2.0 which accompany this distribution.
 *
 * The Apache License is available at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *******************************************************************************/
package io.cloudslang.lang.cli;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import io.cloudslang.lang.cli.services.ScoreServices;
import io.cloudslang.lang.cli.utils.CompilerHelper;
import io.cloudslang.lang.compiler.modeller.result.CompilationModellingResult;
import io.cloudslang.lang.entities.CompilationArtifact;
import io.cloudslang.lang.entities.SystemProperty;
import io.cloudslang.lang.entities.bindings.Input;
import io.cloudslang.lang.entities.bindings.values.Value;
import io.cloudslang.lang.entities.bindings.values.ValueFactory;
import io.cloudslang.score.api.ExecutionPlan;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.shell.Bootstrap;
import org.springframework.shell.core.CommandResult;
import org.springframework.shell.core.JLineShellComponent;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyListOf;
import static org.mockito.Matchers.anyMapOf;
import static org.mockito.Matchers.anySetOf;
import static org.mockito.Matchers.contains;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * Date: 12/9/2014
 *
 * @author Bonczidai Levente
 */
public class SlangCliTest {

    static final CompilationArtifact emptyCompilationArtifact =
            new CompilationArtifact(new ExecutionPlan(), new HashMap<String, ExecutionPlan>(),
                    new ArrayList<Input>(), new HashSet<String>());
    private static final String[] CONTEXT_PATH = {"classpath*:/META-INF/spring/test-spring-shell-plugin.xml"};
    private static final String FLOW_PATH_BACKSLASH_INPUT = "C:\\\\basic_flow.yaml";
    private static final String FLOW_PATH_BACKSLASH = "C:\\basic_flow.yaml";
    private static final String DEPENDENCIES_PATH_BACKSLASH = "C:\\\\executables.dir1\\\\";
    private static final long DEFAULT_TIMEOUT = 10000;
    public static final String INPUT_FILE_PATH = "/inputs/inputs.yaml";

    private JLineShellComponent shell;
    private SlangCli slangCli;
    private ScoreServices scoreServicesMock;
    private CompilerHelper compilerHelperMock;

    public SlangCliTest() {
        Bootstrap bootstrap = new Bootstrap(null, CONTEXT_PATH);
        shell = bootstrap.getJLineShellComponent();
        scoreServicesMock = (ScoreServices) bootstrap.getApplicationContext().getBean("scoreServices");
        compilerHelperMock = (CompilerHelper) bootstrap.getApplicationContext().getBean("compilerHelper");
        slangCli = bootstrap.getApplicationContext().getBean(SlangCli.class);
    }

    @Before
    public void before() throws Exception {
        slangCli.setEnvVar(false);
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunQuietlyValidFilePathAsync() throws Exception {
        slangCli.setEnvVar(true);

        final long executionId = 1;

        when(compilerHelperMock.compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class)))
                .thenReturn(emptyCompilationArtifact);
        when(scoreServicesMock.trigger(eq(emptyCompilationArtifact),
                anyMapOf(String.class, Value.class), anySetOf(SystemProperty.class)))
                .thenReturn(executionId);

        final CommandResult cr = shell.executeCommand("run --f " + FLOW_PATH_BACKSLASH_INPUT + " --v quiet");

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));
        verify(scoreServicesMock)
                .trigger(eq(emptyCompilationArtifact),
                        anyMapOf(String.class, Value.class), anySetOf(SystemProperty.class));

        assertEquals("method result mismatch", StringUtils.EMPTY, cr.getResult());
        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunQuietlyValidFilePathSync() throws Exception {
        final long executionId = 1;

        when(compilerHelperMock.compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class)))
                .thenReturn(emptyCompilationArtifact);
        when(scoreServicesMock
                .triggerSync(eq(emptyCompilationArtifact), anyMapOf(String.class, Value.class),
                        anySetOf(SystemProperty.class), eq(true), eq(false))).thenReturn(executionId);

        final CommandResult cr = shell.executeCommand("run --f " + FLOW_PATH_BACKSLASH_INPUT + " --v quiet");

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));
        verify(scoreServicesMock)
                .triggerSync(eq(emptyCompilationArtifact), anyMapOf(String.class, Value.class),
                        anySetOf(SystemProperty.class), eq(true), eq(false));

        assertEquals("method result mismatch", StringUtils.EMPTY, cr.getResult());
        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunDebugValidFilePathSync() throws Exception {
        final long executionId = 1;

        when(compilerHelperMock.compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class)))
                .thenReturn(emptyCompilationArtifact);
        when(scoreServicesMock
                .triggerSync(eq(emptyCompilationArtifact),
                        anyMapOf(String.class, Value.class), anySetOf(SystemProperty.class), eq(true), eq(false)))
                .thenReturn(executionId);

        CommandResult cr = shell.executeCommand("run --f " + FLOW_PATH_BACKSLASH_INPUT + " --v debug");

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));
        verify(scoreServicesMock)
                .triggerSync(eq(emptyCompilationArtifact), anyMapOf(String.class, Value.class),
                        anySetOf(SystemProperty.class), eq(false), eq(true));

        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunInvalidVerboseArgumentValidFilePathSync() throws Exception {
        final CommandResult cr = shell.executeCommand("run --f " + FLOW_PATH_BACKSLASH_INPUT + " --v invalidArgument");

        assertEquals("method threw exception", "Verbose argument is invalid.", cr.getException().getMessage());
        assertEquals("success should be true", false, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunValidFilePathSync() throws Exception {
        final long executionId = 1;

        when(compilerHelperMock.compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class)))
                .thenReturn(emptyCompilationArtifact);
        when(scoreServicesMock
                .triggerSync(eq(emptyCompilationArtifact), anyMapOf(String.class, Value.class),
                        anySetOf(SystemProperty.class), eq(false), eq(false))).thenReturn(executionId);

        CommandResult cr = shell.executeCommand("run --f " + FLOW_PATH_BACKSLASH_INPUT);

        // path may be processed as local in some environments
        // in this case the local directory path is prepended to the actual path
        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));
        verify(scoreServicesMock)
                .triggerSync(eq(emptyCompilationArtifact), anyMapOf(String.class, Value.class),
                        anySetOf(SystemProperty.class), eq(false), eq(false));

        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunValidFilePathAsync() throws Exception {
        //set async mode
        slangCli.setEnvVar(true);

        final long executionId = 1;

        when(compilerHelperMock.compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class)))
                .thenReturn(emptyCompilationArtifact);
        when(scoreServicesMock
                .trigger(eq(emptyCompilationArtifact), anyMapOf(String.class, Value.class),
                anySetOf(SystemProperty.class))).thenReturn(executionId);

        CommandResult cr = shell.executeCommand("run --f " + FLOW_PATH_BACKSLASH_INPUT);

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));
        verify(scoreServicesMock)
                .trigger(eq(emptyCompilationArtifact),
                        anyMapOf(String.class, Value.class), anySetOf(SystemProperty.class));

        assertEquals("method result mismatch",
                SlangCli.triggerAsyncMsg(executionId,
                        emptyCompilationArtifact.getExecutionPlan().getName()), cr.getResult());
        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunValidWithOtherPathForDependencies() throws Exception {
        final long executionId = 1;

        when(compilerHelperMock
                .compile(contains(FLOW_PATH_BACKSLASH), anyListOf(String.class))).thenReturn(emptyCompilationArtifact);
        when(scoreServicesMock
                .triggerSync(eq(emptyCompilationArtifact), anyMapOf(String.class, Value.class),
                        anySetOf(SystemProperty.class), eq(false), eq(false))).thenReturn(executionId);

        CommandResult cr = shell.executeCommand("run --f " +
                FLOW_PATH_BACKSLASH_INPUT + " --cp " + DEPENDENCIES_PATH_BACKSLASH);

        verify(compilerHelperMock)
                .compile(contains(FLOW_PATH_BACKSLASH), anyListOf(String.class));
        verify(scoreServicesMock)
                .triggerSync(eq(emptyCompilationArtifact), anyMapOf(String.class, Value.class),
                        anySetOf(SystemProperty.class), eq(false), eq(false));

        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunSyncWithInputsAndFileInputs() throws Exception {
        final long executionId = 1;
        final String inputsString = "--i input1=value1,input2=value2";

        Map<String, Value> inputsMap = new HashMap<>();
        inputsMap.put("input1", ValueFactory.create("value1"));
        inputsMap.put("input2", ValueFactory.create("value2"));

        Map fileInputsMap = new HashMap<>();
        fileInputsMap.put("host", "localhost");
        fileInputsMap.put("port", "22");

        inputsMap.putAll(fileInputsMap);

        when(compilerHelperMock
                .compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class))).thenReturn(emptyCompilationArtifact);
        when(compilerHelperMock
                .loadInputsFromFile(anyList())).thenReturn(fileInputsMap);
        when(scoreServicesMock
                .triggerSync(eq(emptyCompilationArtifact), eq(inputsMap),
                        anySetOf(SystemProperty.class), eq(false), eq(false))).thenReturn(executionId);

        CommandResult cr = shell.executeCommand("run --f " + FLOW_PATH_BACKSLASH_INPUT + " " + inputsString);

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));
        verify(scoreServicesMock)
                .triggerSync(eq(emptyCompilationArtifact), eq(inputsMap),
                        anySetOf(SystemProperty.class), eq(false), eq(false));

        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunAsyncWithInputsAndFileInputs() throws Exception {
        slangCli.setEnvVar(true);

        final long executionId = 1;
        final String inputsString = "--i input1=value1,input2=value2";

        Map<String, Value> inputsMap = new HashMap<>();
        inputsMap.put("input1", ValueFactory.create("value1"));
        inputsMap.put("input2", ValueFactory.create("value2"));

        Map fileInputsMap = new HashMap<>();
        fileInputsMap.put("host", "localhost");
        fileInputsMap.put("port", "22");

        inputsMap.putAll(fileInputsMap);

        when(compilerHelperMock
                .compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class))).thenReturn(emptyCompilationArtifact);
        when(compilerHelperMock
                .loadInputsFromFile(anyList())).thenReturn(fileInputsMap);
        when(scoreServicesMock
                .trigger(eq(emptyCompilationArtifact), eq(inputsMap),
                        anySetOf(SystemProperty.class))).thenReturn(executionId);

        CommandResult cr = shell.executeCommand("run --f " + FLOW_PATH_BACKSLASH_INPUT + " " + inputsString);

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));
        verify(scoreServicesMock).trigger(eq(emptyCompilationArtifact), eq(inputsMap), anySetOf(SystemProperty.class));

        assertEquals("method result mismatch",
                SlangCli.triggerAsyncMsg(executionId,
                        emptyCompilationArtifact.getExecutionPlan().getName()), cr.getResult());
        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunSyncWithInputs() throws Exception {
        final long executionId = 1;
        final String inputsString = "--i input1=value1,input2=value2";
        Map<String, Value> inputsMap = new HashMap<>();
        inputsMap.put("input1", ValueFactory.create("value1"));
        inputsMap.put("input2", ValueFactory.create("value2"));

        when(compilerHelperMock
                .compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class)))
                .thenReturn(emptyCompilationArtifact);
        when(scoreServicesMock
                .triggerSync(eq(emptyCompilationArtifact), eq(inputsMap),
                        anySetOf(SystemProperty.class), eq(false), eq(false))).thenReturn(executionId);

        CommandResult cr = shell.executeCommand("run --f " + FLOW_PATH_BACKSLASH_INPUT + " " + inputsString);

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));
        verify(scoreServicesMock).triggerSync(eq(emptyCompilationArtifact),
                eq(inputsMap), anySetOf(SystemProperty.class), eq(false), eq(false));

        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunException() throws IOException {
        RuntimeException exception = new RuntimeException("exception message");

        when(compilerHelperMock.compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class)))
                .thenReturn(emptyCompilationArtifact);
        when(scoreServicesMock
                .triggerSync(eq(emptyCompilationArtifact), anyMapOf(String.class, Value.class),
                        anySetOf(SystemProperty.class), eq(false), eq(false)))
                .thenThrow(exception);

        final CommandResult cr = shell.executeCommand("run --f " + FLOW_PATH_BACKSLASH_INPUT);

        // path may be processed as local in some environments
        // in this case the local directory path is prepended to the actual path
        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));
        verify(scoreServicesMock).triggerSync(eq(emptyCompilationArtifact), anyMapOf(String.class, Value.class),
                anySetOf(SystemProperty.class), eq(false), eq(false));

        assertEquals("exception not as expected", exception, cr.getException());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunAsyncWithInputs() throws Exception {
        //set async mode
        slangCli.setEnvVar(true);

        final long executionId = 1;
        final String inputsString = "--i input1=value1,input2=value2";
        Map<String, Value> inputsMap = new HashMap<>();
        inputsMap.put("input1", ValueFactory.create("value1"));
        inputsMap.put("input2", ValueFactory.create("value2"));

        when(compilerHelperMock.compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class)))
                .thenReturn(emptyCompilationArtifact);
        when(scoreServicesMock.trigger(eq(emptyCompilationArtifact), eq(inputsMap),
                anySetOf(SystemProperty.class))).thenReturn(executionId);

        CommandResult cr = shell.executeCommand("run --f " + FLOW_PATH_BACKSLASH_INPUT + " " + inputsString);

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));
        verify(scoreServicesMock).trigger(eq(emptyCompilationArtifact), eq(inputsMap),
                anySetOf(SystemProperty.class));

        assertEquals("method result mismatch",
                SlangCli.triggerAsyncMsg(executionId,
                        emptyCompilationArtifact.getExecutionPlan().getName()), cr.getResult());
        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunSyncWithInputFiles() throws Exception {
        final long executionId = 1;

        when(compilerHelperMock.compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class)))
                .thenReturn(emptyCompilationArtifact);
        when(scoreServicesMock.triggerSync(eq(emptyCompilationArtifact), anyMapOf(String.class, Value.class),
                anySetOf(SystemProperty.class), eq(false), eq(false))).thenReturn(executionId);

        final CommandResult cr = shell.executeCommand("run --f " +
                FLOW_PATH_BACKSLASH_INPUT + " --if " + FLOW_PATH_BACKSLASH_INPUT);

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));
        verify(compilerHelperMock).loadInputsFromFile(Collections.singletonList(FLOW_PATH_BACKSLASH));
        verify(scoreServicesMock).triggerSync(eq(emptyCompilationArtifact),
                anyMapOf(String.class, Value.class), anySetOf(SystemProperty.class), eq(false), eq(false));

        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testRunSyncWithSystemProperties() throws Exception {
        long executionId = 1;

        when(compilerHelperMock.compile(contains(FLOW_PATH_BACKSLASH),
                isNull(List.class))).thenReturn(emptyCompilationArtifact);
        when(scoreServicesMock.triggerSync(eq(emptyCompilationArtifact),
                anyMapOf(String.class, Value.class), anySetOf(SystemProperty.class), eq(false), eq(false)))
                .thenReturn(executionId);

        final CommandResult cr = shell.executeCommand("run --f " +
                FLOW_PATH_BACKSLASH_INPUT + " --spf " + FLOW_PATH_BACKSLASH_INPUT);

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH),
                isNull(List.class));
        verify(compilerHelperMock).loadSystemProperties(Collections.singletonList(FLOW_PATH_BACKSLASH));
        verify(scoreServicesMock).triggerSync(eq(emptyCompilationArtifact),
                anyMapOf(String.class, Value.class), anySetOf(SystemProperty.class), eq(false), eq(false));

        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testSetEnvVarTrue() throws Exception {
        final CommandResult cr = shell.executeCommand("env --setAsync true");

        assertEquals("method result mismatch", SlangCli.setEnvMessage(true), cr.getResult());
        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testSetEnvVarFalse() {
        final CommandResult cr = shell.executeCommand("env --setAsync false");

        assertEquals("method result mismatch", SlangCli.setEnvMessage(false), cr.getResult());
        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testGetFlowInputs() throws Exception {
        final List<Input> inputsList = Lists.newArrayList(
                new Input.InputBuilder("input1", "expression1").build(),
                new Input.InputBuilder("input2", "expression2").build()
        );
        CompilationArtifact compilationArtifact =
                new CompilationArtifact(new ExecutionPlan(), new HashMap<String, ExecutionPlan>(), inputsList, null);

        when(compilerHelperMock.compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class)))
                .thenReturn(compilationArtifact);

        final CommandResult cr = shell.executeCommand("inputs --f " + FLOW_PATH_BACKSLASH_INPUT);

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));

        assertEquals("input list mismatch", Lists.newArrayList("input1", "input2"), cr.getResult());
        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testGetFlowInputsWithOverride() throws Exception {
        final List<Input> inputsList = Lists.newArrayList(
                new Input.InputBuilder("input1", "expression1").build(),
                new Input.InputBuilder("input_override", "expression_override", false)
                        .withRequired(true)
                        .withPrivateInput(true)
                        .build(),
                new Input.InputBuilder("input2", "expression2").build()
        );
        final CompilationArtifact compilationArtifact =
                new CompilationArtifact(new ExecutionPlan(), new HashMap<String, ExecutionPlan>(), inputsList, null);

        when(compilerHelperMock.compile(contains(FLOW_PATH_BACKSLASH),
                isNull(List.class))).thenReturn(compilationArtifact);

        CommandResult cr = shell.executeCommand("inputs --f " + FLOW_PATH_BACKSLASH_INPUT);

        verify(compilerHelperMock).compile(contains(FLOW_PATH_BACKSLASH), isNull(List.class));

        assertEquals("input list mismatch", Lists.newArrayList("input1", "input2"), cr.getResult());
        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testGetVersion() throws Exception {
        final CommandResult cr = shell.executeCommand("cslang --version");

        assertEquals("method result mismatch", slangCli.version(), cr.getResult());
        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testListSystemProperties() throws Exception {
        when(compilerHelperMock.loadSystemProperties(Lists.newArrayList("system_properties.prop.sl")))
                .thenReturn(Sets.newLinkedHashSet(Lists.newArrayList(
                        new SystemProperty("namespace1", "key1", "value1", ""),
                        new SystemProperty("namespace2", "key2", "value2", ""),
                        new SystemProperty("namespace3", "key3", "value3", ""))));

        final CommandResult cr = shell.executeCommand("list --f system_properties.prop.sl");

        assertEquals("Following system properties were loaded:" + System.lineSeparator() +
                "\tnamespace1.key1: value1" + System.lineSeparator() +
                "\tnamespace2.key2: value2" + System.lineSeparator() +
                "\tnamespace3.key3: value3", cr.getResult());
        assertEquals("method threw exception", null, cr.getException());
        assertEquals("success should be true", true, cr.isSuccess());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testPrintCompileErrors() {
        when(compilerHelperMock
                .compileSource(System.getProperty("user.dir") + File.separator + "some_slang_file.sl", null))
                .thenReturn(new CompilationModellingResult(null, Lists.newArrayList(new RuntimeException("1"),
                        new RuntimeException("2"), new RuntimeException("3"))));

        final CommandResult cr = shell.executeCommand("compile --f some_slang_file.sl");
        Assert.assertNotNull(cr.getException());
        assertEquals("exception mismatch", "Following exceptions were found:" + System.lineSeparator() +
                "\tclass java.lang.RuntimeException: 1" + System.lineSeparator() +
                "\tclass java.lang.RuntimeException: 2" + System.lineSeparator() +
                "\tclass java.lang.RuntimeException: 3" + System.lineSeparator(), cr.getException().getMessage());
    }

    @Test(timeout = DEFAULT_TIMEOUT)
    public void testCompileNoArgument() {
        final CommandResult cr = shell.executeCommand("compile");
        Assert.assertNotNull(cr.getException());
        Assert.assertEquals("You should specify directory(otherwise known as option 'd') " +
                "or file(otherwise known as option 'f').", cr.getException().getMessage());
    }

}
