package CH.ifa.draw.io;

import java.io.File;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

/** A test class for {@link SimpleFileFilter}. */
public class SimpleFileFilterTest {
    private SimpleFileFilter _fileFilter;
    private static final String FILE_TYPE_ENDING = "txt";

    @BeforeEach
    void setUp() {
        _fileFilter = new SimpleFileFilter(FILE_TYPE_ENDING, "dummyDescription");
    }

    @AfterEach
    void tearDown() {
        _fileFilter = null;
    }

    /**
     * Ensures that {@link SimpleFileFilter#allowHidden(boolean)} correctly
     * marks hidden files as allowed.
     */
    @Test
    void testIsHiddenAllowed() {
        //when
        _fileFilter.allowHidden(true);

        //then
        assertThat(_fileFilter.isHiddenAllowed()).isTrue();
    }

    /**
     * Ensures that {@link SimpleFileFilter#allowDirectory(boolean)} correctly
     * marks directories as allowed.
     */
    @Test
    void testIsDirectoryAllowed() {
        //when
        _fileFilter.allowDirectory(true);

        //then
        assertThat(_fileFilter.isDirectoryAllowed()).isTrue();
    }

    /** Tests whether a file with the same extension as the one saved in the filter is accepted. */
    @Test
    void testAccept() {
        //when/then
        assertThat(_fileFilter.accept(new File("path/to/file." + FILE_TYPE_ENDING))).isTrue();
    }

    /** Tests whether a hidden File is accepted. */
    @Test
    void testAcceptOfHiddenFile() {
        //when
        _fileFilter.allowHidden(true);

        //then
        assertThat(_fileFilter.accept(new File("path/to/.file." + FILE_TYPE_ENDING))).isTrue();
    }

    /** Tests whether a directory is accepted. */
    @Test
    void testAcceptOfDirectory() {
        //given
        File mockedDirectory = Mockito.mock(File.class);

        //when
        _fileFilter.allowDirectory(true);

        when(mockedDirectory.getName()).thenReturn("directoryName");
        when(mockedDirectory.isHidden()).thenReturn(false);
        when(mockedDirectory.isDirectory()).thenReturn(true);

        //then
        assertThat(_fileFilter.accept(mockedDirectory)).isTrue();
    }

    /** Tests whether {@code null} is not accepted. */
    @Test
    void testNotAccept() {
        //when/then
        assertThat(_fileFilter.accept(null)).isFalse();
    }

    /** Tests whether a hidden file is not accepted if hidden files are not set to accepted. */
    @Test
    void testNotAcceptHiddenFileWhenNotAllowed() {
        //given
        File mockedFile = Mockito.mock(File.class);

        //when
        _fileFilter.allowHidden(false); // Not necessary but aids understanding
        when(mockedFile.isHidden()).thenReturn(true);
        when(mockedFile.getName()).thenReturn(".file." + FILE_TYPE_ENDING);

        //then
        assertThat(_fileFilter.accept(mockedFile)).isFalse();
    }

    /** Tests whether a not hidden file starting with a dot is rejected. */
    @Test
    void testNotAcceptWhenFileNotHiddenButStartsWithDot() {
        //given
        File mockedFile = Mockito.mock(File.class);

        //when
        _fileFilter.allowHidden(false); // Not necessary but aids understanding
        when(mockedFile.isHidden()).thenReturn(false);
        when(mockedFile.getName()).thenReturn(".file." + FILE_TYPE_ENDING);

        //then
        assertThat(_fileFilter.accept(mockedFile)).isFalse();
    }

    /** Tests whether {@link SimpleFileFilter#equals(Object)} is correctly overwritten. */
    @Test
    void testEquals() {
        //given
        SimpleFileFilter fileFilterCopy =
            new SimpleFileFilter(FILE_TYPE_ENDING, "dummyDescription");

        //then
        assertThat(_fileFilter.equals(fileFilterCopy)).isTrue();
    }

    /**
     * Tests whether two SimpleFileFilters are not considered
     * equal if their extensions are different.
     */
    @Test
    void testNotEquals() {
        //when
        SimpleFileFilter fileFilterCopy =
            new SimpleFileFilter("differentExtension", "dummyDescription");

        //then
        assertThat(_fileFilter.equals(fileFilterCopy)).isFalse();
    }

    /** Tests whether objects of two different classes are correctly identified as not equal. */
    @Test
    void testNotEqualsMethod() {
        //when/then
        assertThat(_fileFilter.equals(new Object())).isFalse();
    }

    /** Tests whether {@link SimpleFileFilter#hashCode()} returns a not {@code null} value. */
    @Test
    void testHashCode() {
        //when/then
        assertThat(_fileFilter.hashCode()).isNotNull();
    }
}
