/**
 * Copyright (c) 2012-2013 Linagora
 * 
 * This program/library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * This program/library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program/library; If not, see <http://www.gnu.org/licenses/>
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.cli.shell;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.ow2.petals.admin.PetalsAdministrationFactoryMock;
import org.ow2.petals.admin.api.PetalsAdministrationFactory;
import org.ow2.petals.admin.api.exception.ArtifactAdministrationException;
import org.ow2.petals.cli.api.connection.AuthenticatedConnectionParameters;
import org.ow2.petals.cli.api.connection.ConnectionParameters;
import org.ow2.petals.cli.api.exception.ShellException;
import org.ow2.petals.cli.shell.command.AbstractCommand;
import org.ow2.petals.cli.shell.command.CommandExecutedWithError;
import org.ow2.petals.cli.shell.command.CommandNoArg;
import org.ow2.petals.cli.shell.command.CommandResult;

/**
 * Unit tests of {@link PetalsCli}
 * 
 * @author Christophe DENEUX - Linagora
 */
public class PetalsCliTest {

    @Before
    public void beforeTest() {
        System.setProperty(PetalsAdministrationFactory.PROPERTY_NAME,
                PetalsAdministrationFactoryMock.class.getName());
    }

    @After
    public void afterTest() throws ArtifactAdministrationException {
        // clean registry
        System.clearProperty(PetalsAdministrationFactory.PROPERTY_NAME);
    }

    /**
     * The shell {@link PetalsCli} establishes automatically a connection. Here,
     * the default connection parameters.
     */
    private final ConnectionParameters defaultConnectionParameters = new AuthenticatedConnectionParameters(
            "localhost", 7700, "petals", "petals", null);

    /**
     * Check the run method against an not-registered entered command.
     */
    @Test
    public final void testRun_WithUnregisteredCommand() {

        final PrintStream standardConsoleError = System.err;

        try {
            final String unknownCommand = "unknowncommand";
            final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
            System.setErr(new PrintStream(errBAIS));
            final AbstractShell shell = new PetalsCli(new String[] { unknownCommand }, false, false);

            shell.setConnectionParameters(this.defaultConnectionParameters);
            shell.run();

            final String error = errBAIS.toString();
            assertFalse(error.isEmpty());
            assertTrue(error.startsWith("ERROR:"));
            assertTrue(error.contains(unknownCommand));
            assertEquals("Invalid exit code", 1, shell.getExitStatus());
        } finally {
            System.setErr(standardConsoleError);
        }

    }

    /**
     * Check the run method against an right entered command.
     * 
     * @throws ShellException
     */
    @Test
    public final void testRun_RegisteredCommand() throws ShellException {

        final PrintStream standardConsoleError = System.err;

        try {
            final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
            System.setErr(new PrintStream(errBAIS));
            final AbstractShell shell = new PetalsCli(new String[] { CommandNoArg.class
                    .getSimpleName().toLowerCase() }, false, false);

            final CommandResult cmdRes = new CommandResult();

            shell.registersCommand(new CommandNoArg(cmdRes));

            shell.setConnectionParameters(this.defaultConnectionParameters);
            shell.run();

            final String error = errBAIS.toString();
            assertTrue(error.isEmpty());
            assertTrue(cmdRes.isExecuted());
            assertEquals("Invalid exit code", 0, shell.getExitStatus());
        } finally {
            System.setErr(standardConsoleError);
        }

    }

    /**
     * Check the run method against an command entered with error.
     * 
     * @throws ShellException
     */
    @Test
    public final void testRun_CommandEnteredWithError() throws ShellException {

        final PrintStream standardConsoleError = System.err;

        try {
            final CommandResult cmdRes = new CommandResult();
            final AbstractCommand command = new CommandNoArg(cmdRes);

            final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
            System.setErr(new PrintStream(errBAIS));
            final AbstractShell shell = new PetalsCli(new String[] { command.getName(), "arg1" },
                    false, false);

            shell.registersCommand(command);

            shell.setConnectionParameters(this.defaultConnectionParameters);
            shell.run();

            final String error = errBAIS.toString();
            assertFalse(error.isEmpty());
            assertTrue("The command is missing in error message",
                    error.startsWith("ERROR on command '" + command.getName() + "':"));
            assertTrue("The command usage is missing in error message",
                    error.contains(command.getUsage()));
            assertEquals("Invalid exit code", 1, shell.getExitStatus());
        } finally {
            System.setErr(standardConsoleError);
        }

    }

    /**
     * Check the run method against an command executed with error.
     * 
     * @throws ShellException
     */
    @Test
    public final void testRun_CommandExecutedWithError() throws ShellException {

        final PrintStream standardConsoleError = System.err;

        try {
            final CommandResult cmdRes = new CommandResult();
            final AbstractCommand command = new CommandExecutedWithError(cmdRes);

            final ByteArrayOutputStream errBAIS = new ByteArrayOutputStream();
            System.setErr(new PrintStream(errBAIS));
            final AbstractShell shell = new PetalsCli(new String[] { command.getName(),
                    "-" + CommandExecutedWithError.DUMMY_SHORT_OPTION }, false, false);

            shell.registersCommand(command);

            shell.setConnectionParameters(this.defaultConnectionParameters);
            shell.run();

            final String error = errBAIS.toString();
            assertFalse(error.isEmpty());
            assertTrue("The command is missing in error message",
                    error.startsWith("ERROR on command '" + command.getName() + "':"));
            assertTrue("The command usage is contained in error message",
                    !error.contains(command.getUsage()));
            assertEquals("Invalid exit code", 2, shell.getExitStatus());
        } finally {
            System.setErr(standardConsoleError);
        }

    }
}
