/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2021 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jboss.installer.validators;

import org.apache.commons.lang3.SystemUtils;
import org.jboss.installer.test.utils.MockLanguageUtils;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;

import static org.assertj.core.api.Assertions.assertThat;
import static org.jboss.installer.validators.WritableFolderValidator.EMPTY_DIRECTORY_DISABLED;

public class WritableFolderValidatorTest {
    private static final String NOT_WRITEABLE_KEY = "test_prefix." + WritableFolderValidator.NOT_WRITEABLE_KEY;
    private static final String NOT_ABSOLUTE_PATH = "test_prefix." + WritableFolderValidator.NOT_ABSOLUTE_PATH;
    private static final String NON_EMPTY_KEY = "test_prefix." + WritableFolderValidator.NON_EMPTY_KEY;
    private static final String IS_FILE = "test_prefix." + WritableFolderValidator.IS_FILE;
    private static final String NO_PATH_KEY = "test_prefix." + PathValidator.NO_PATH_KEY;
    private static final String INVALID_CHAR = "test_prefix." + PathValidator.INVALID_CHAR;
    private static final String FILENAME_TOO_LONG = "test_prefix." + PathValidator.FILENAME_TOO_LONG;
    private static final String PATH_TOO_LONG = "test_prefix." + PathValidator.ERROR_PATH_TOO_LONG;

    public static final String HOME_DIR = System.getProperty("user.home");
    public static final String WORKING_DIR = System.getProperty("user.dir");
    public static final String FS = File.separator;

    @Rule
    public TemporaryFolder temp = new TemporaryFolder();

    private final WritableFolderValidator validator = new WritableFolderValidator("test_prefix", new MockLanguageUtils());

    @Test
    public void cannotWriteIntoFolder() throws Exception {
        Assume.assumeFalse(SystemUtils.IS_OS_WINDOWS);

        final Path tempFilePath = temp.newFolder().toPath();
        tempFilePath.toFile().setWritable(false);
        assertThat(validator.validate(tempFilePath.toString(), EMPTY_DIRECTORY_DISABLED).getMessage())
                .startsWith(NOT_WRITEABLE_KEY);
    }

    @Test
    public void nonExistingFolderWithoutParent() throws Exception {
        Assume.assumeTrue(SystemUtils.IS_OS_WINDOWS);

        assertThat(validator.validate("x:\\temp", EMPTY_DIRECTORY_DISABLED).getMessage())
                .startsWith(NOT_WRITEABLE_KEY);
    }

    @Test
    public void nonEmptyFolder() {
        Path userDirectory = Paths.get(WORKING_DIR);
        assertThat(validator.validate(userDirectory.toString(), EMPTY_DIRECTORY_DISABLED).getMessage())
                .startsWith(NON_EMPTY_KEY);
    }

    @Test
    public void cannotCreateFolder() throws Exception {
        Assume.assumeFalse(SystemUtils.IS_OS_WINDOWS);

        final Path tempFilePath = temp.newFolder().toPath();
        tempFilePath.toFile().setWritable(false);
        Path nonCreatableDirectory = Paths.get(tempFilePath + FS + "newFolder");
        assertThat(validator.validate(nonCreatableDirectory.toString(), EMPTY_DIRECTORY_DISABLED).getMessage())
                .startsWith(NOT_WRITEABLE_KEY);
    }


    @Test
    public void pathToFile() throws Exception {
        final Path tempFilePath = temp.newFile("temp.tmp").toPath();
        assertThat(validator.validate(tempFilePath.toString(), EMPTY_DIRECTORY_DISABLED).getMessage())
                .startsWith(IS_FILE);
    }

    @Test
    public void notAbsolutePath() {
        Path folderName = Paths.get("newFolder");
        assertThat(validator.validate(folderName.toString(), EMPTY_DIRECTORY_DISABLED).getMessage())
                .startsWith(NOT_ABSOLUTE_PATH);
    }

    @Test
    public void validPath() {
        Path validDirectoryPath = Paths.get(HOME_DIR + FS + "newFolder");
        Assert.assertNull(validator.validate(validDirectoryPath.toString(), EMPTY_DIRECTORY_DISABLED).getMessage());
    }

    @Test
    public void nullPath() {
        assertThat(validator.validate((String)null, EMPTY_DIRECTORY_DISABLED).getMessage())
                .startsWith(NO_PATH_KEY);
    }

    @Test
    public void pathContainsForbiddenChar() {
        assertThat(validator.validate(HOME_DIR + FS + "newFolder%", EMPTY_DIRECTORY_DISABLED).getMessage())
                .startsWith(INVALID_CHAR);
    }

    @Test
    public void pathLongFilename() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i< 300; i++) {
            sb.append("a");
        }

        assertThat(validator.validate(HOME_DIR + FS + sb, EMPTY_DIRECTORY_DISABLED).getMessage())
                .startsWith(FILENAME_TOO_LONG);
    }

    @Test
    public void pathLongPath() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i< 3300; i++) {
            sb.append("0123456789").append(FS);
        }

        assertThat(validator.validate(HOME_DIR + FS + sb, EMPTY_DIRECTORY_DISABLED).getMessage())
                .startsWith(PATH_TOO_LONG);
    }

    @Test
    public void testInvalidCharacterErrorIsPropagated() {
        assertThat(validator.validate("foo\0/bar", false).getMessage())
                .startsWith(INVALID_CHAR);
    }
}
