/**
 * Copyright (c) 2010-2012 EBM WebSourcing, 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.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.Map;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.ow2.petals.cli.api.command.Command;
import org.ow2.petals.cli.api.command.exception.CommandException;
import org.ow2.petals.cli.api.exception.DuplicatedCommandException;
import org.ow2.petals.cli.api.exception.ShellException;
import org.ow2.petals.cli.shell.command.AbstractCommand;

/**
 * Unit tests of {@link AbstractShell}
 * 
 * @author Sebastien Andre - EBM WebSourcing
 * @author Christophe DENEUX - EBM WebSourcing
 */
public class AbstractShellTest {


    private TestShell shell;

    private class TestShell extends AbstractShell {

        public TestShell() throws ShellException {
            super(System.out, System.err, false, false);
        }

        @Override
        public boolean isComment(String line) {
            return super.isComment(line);
        }

        @Override
        public void run() {
            // NOP
        }

        @Override
        public String askQuestion(String question, boolean isReplyPassword) throws ShellException {
            return null;
        }

        @Override
        public boolean confirms(String message) throws ShellException {
            return false;
        }

    }

    private class TestCommand extends AbstractCommand {

        @Override
        public void execute(String[] args) throws CommandException {
            // NOP
        }

    }

    @Before
    public void setUp() throws Exception {
        this.shell = new TestShell();
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public final void testIsComment() {
        assertTrue(shell.isComment("#   "));
        assertTrue(shell.isComment(""));
        assertTrue(shell.isComment("   "));
        assertTrue(shell.isComment("           "));
        assertTrue(shell.isComment("    #"));
        assertTrue(shell.isComment("    ## ### ## "));
        assertFalse(shell.isComment("joe"));
        assertFalse(shell.isComment("  joe# "));
        assertFalse(shell.isComment(".#"));
    }

    @Test
    public final void testInterpolate() {

        assertEquals("booo", this.shell.interpolate("booo"));
        assertEquals("   space   ", this.shell.interpolate("   space   "));

        System.clearProperty("var");
        System.clearProperty("var2");
        assertEquals("${var}", this.shell.interpolate("${var}"));
        assertEquals("${var} ${var}", this.shell.interpolate("${var} ${var}"));
        assertEquals("${var} ${var} ${var2}", this.shell.interpolate("${var} ${var} ${var2}"));
        
        System.setProperty("var", "value");
        assertEquals("value", this.shell.interpolate("${var}"));
        assertEquals(" value ", this.shell.interpolate(" ${var} "));
        assertEquals(" value value ", this.shell.interpolate(" ${var} ${var} "));
        assertEquals(" value value ${var2} ", this.shell.interpolate(" ${var} ${var} ${var2} "));

        assertEquals("${var}", this.shell.interpolate("\\${var}"));
        assertEquals(" ${var} value \\${var} ",
                this.shell.interpolate(" \\${var} ${var} \\\\${var} "));
    }

    /**
     * Check the register method against a command.
     */
    @Test
    public final void testRegister_Command() throws DuplicatedCommandException {

        final Command myCommand = new TestCommand();
        this.shell.registersCommand(myCommand);

        final Map<String, Command> commands = this.shell.getCommands();
        assertNotNull(commands);
        assertEquals(1, commands.size());

        final Command registeredCommand = commands.get(myCommand.getName());
        assertNotNull(registeredCommand);

    }

    /**
     * Check the register method against a duplicated command.
     */
    @Test
    public final void testRegister_DuplicatedCommand() throws DuplicatedCommandException {

        final Command myCommand = new TestCommand();
        this.shell.registersCommand(myCommand);

        final Map<String, Command> commands = this.shell.getCommands();
        assertNotNull(commands);
        assertEquals(1, commands.size());

        try {
            this.shell.registersCommand(myCommand);
            fail("The expected exception '" + DuplicatedCommandException.class.getName()
                    + "' has not be thrown.");
        } catch (final DuplicatedCommandException e) {
            assertEquals(e.getCommandName(), myCommand.getName());
        }

    }

}
