/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2023 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.RandomStringUtils;
import org.jboss.installer.core.ValidationResult;
import org.jboss.installer.test.utils.MockLanguageUtils;
import org.junit.Before;
import org.junit.Test;

import java.nio.file.Path;

import static org.jboss.installer.validators.PathValidator.EAP_RESERVED_PATH_LENGTH;
import static org.jboss.installer.validators.LinuxPathValidator.LINUX_PATH_LENGTH_HARD_LIMIT;
import static org.junit.Assert.*;

public class LinuxPathValidatorTest {

    private LinuxPathValidator validator;

    @Before
    public void setUp() throws Exception {
        validator = new LinuxPathValidator("test", new MockLanguageUtils());
    }

    @Test
    public void testValidAbsolutePath() throws Exception {
        assertResult(ValidationResult.Result.OK, validator.validateCharacters("/Some/Path"));
    }

    @Test
    public void testValidRelativeDrivePath() throws Exception {
        assertResult(ValidationResult.Result.OK, validator.validateCharacters("Some/Path"));
    }

    @Test
    public void testPathWithDoubleSlash() throws Exception {
        assertResult(ValidationResult.Result.ERROR, validator.validateCharacters("Some//Path"));
    }

    @Test
    public void testValidPathWithSingleSpaces() throws Exception {
        assertResult(ValidationResult.Result.OK, validator.validateCharacters("Some/Pa th/He re"));
    }

    @Test
    public void testInvalidPathWithDoubleSpaces() throws Exception {
        assertResult(ValidationResult.Result.ERROR, validator.validateCharacters("Some/Pa  th/He re"));
    }

    @Test
    public void testInvalidPathWithTrippleSpaces() throws Exception {
        assertResult(ValidationResult.Result.ERROR, validator.validateCharacters("Some/Pa   th/He re"));
    }

    @Test
    public void testPathsWithInvalidCharacters() throws Exception {
        for (String s: LinuxPathValidator.LINUX_INVALID_CHARACTERS) {
            assertResult(ValidationResult.Result.ERROR, validator.validateCharacters("/Some/Pa" + s + "th"));
        }
    }

    @Test
    public void testErrorOnExceedHardLimit() throws Exception {
        final int maxLength = LINUX_PATH_LENGTH_HARD_LIMIT - EAP_RESERVED_PATH_LENGTH;
        final StringBuilder sb = buildPath(50, maxLength);

        assertResult(ValidationResult.Result.ERROR, validator.validateAbsoluteLength(Path.of(sb.toString())));
    }

    @Test
    public void testExactlyHardLimitIsOk() throws Exception {
        final int filenameLength = 50;
        final int maxLength = LINUX_PATH_LENGTH_HARD_LIMIT - EAP_RESERVED_PATH_LENGTH - filenameLength;

        final StringBuilder sb = buildPath(filenameLength, maxLength);
        sb.append("\\").append(RandomStringUtils.randomAlphabetic(filenameLength + (maxLength - sb.length())));

        assertResult(ValidationResult.Result.OK, validator.validateAbsoluteLength(Path.of(sb.toString())));
    }

    private static StringBuilder buildPath(int filenameLength, int maxLength) {
        final String filename = RandomStringUtils.randomAlphabetic(50);
        final StringBuilder sb = new StringBuilder("C:");
        while (sb.length() < maxLength) {
            sb.append("\\").append(filename);
        }
        return sb;
    }

    private static void assertResult(ValidationResult.Result expected, ValidationResult validationResult) {
        assertEquals(expected, validationResult.getResult());
    }

}