/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--

Dia-Files

Copyright (C) 2019-2024  Anonymous

There are several releases over multiple years,
they are listed as ranges, such as: "2019-2024".

This program 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 3 of the License, or
(at your option) any later version.

This program 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.  If not, see <https://www.gnu.org/licenses/>.

::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/

use {
    std::path::PathBuf,
    dia_files::{
        Result,
        filter::Filter::AllPaths,
        find_files,
    },
};

use dia_files::{
    FileDiscovery,
    filter::{
        Case,
        Filter::{
            All, IgnoredDirNames, IgnoredFileExts, IgnoredFileNames, NonSymlinkFiles, SomeDirNames, SomeFileExts, SomeFileNames, SymlinkFiles,
            UserDefined,
        },
    },
};

#[cfg(feature="async-std")]
use {
    core::future::{self, Future},
    async_std::{
        path::Path,
        task,
    },
};

macro_rules! count { ($f: expr) => {{
    #[cfg(feature="async-std")]
    let r = task::block_on(async {
        $f.await.unwrap().count().await.unwrap()
    });
    #[cfg(not(feature="async-std"))]
    let r = $f?.count();
    r
}}}

const ALL_FILES: usize = 8;
const SYMLINK_FILES: usize = 2;
const LEVEL_1_NESTED_FILES: usize = 1;
const LEVEL_2_NESTED_FILES: usize = 2;
const ALL_NESTED_FILES: usize = LEVEL_1_NESTED_FILES + LEVEL_2_NESTED_FILES;
const FILES_WITHOUT_EXT: usize = 2;
const MD_FILES: usize = 3;

pub fn test_dir() -> PathBuf {
    PathBuf::from(file!()).parent().unwrap().join("files")
}

#[test]
fn test_find_files() -> Result<()> {
    let dir = test_dir();

    assert_eq!(count!(find_files(&dir, true, AllPaths)), ALL_FILES);

    #[cfg(not(feature="async-std"))]
    assert_eq!(count!(find_files(&dir, true, UserDefined { accept: |_| true })), ALL_FILES);

    #[cfg(feature="async-std")] {
        fn accept(_: &Path) -> Box<dyn Future<Output=bool> + Unpin> { Box::new(future::ready(true)) }
        assert_eq!(count!(find_files(&dir, true, UserDefined { accept })), ALL_FILES);
    }

    assert_eq!(count!(find_files(&dir, true, SomeDirNames { names: &["abc"], case: Case::Sensitive })), ALL_FILES - LEVEL_2_NESTED_FILES);
    assert_eq!(count!(find_files(&dir, true, SomeDirNames { names: &["ABC"], case: Case::Sensitive })), ALL_FILES - ALL_NESTED_FILES);
    assert_eq!(count!(find_files(&dir, true, SomeDirNames { names: &["aBC"], case: Case::Insensitive })), ALL_FILES - LEVEL_2_NESTED_FILES);

    assert_eq!(count!(find_files(&dir, true, IgnoredDirNames { dir_names: &["abc"], case: Case::Sensitive })), ALL_FILES - ALL_NESTED_FILES);
    assert_eq!(count!(find_files(&dir, true, IgnoredDirNames { dir_names: &["ABC"], case: Case::Sensitive })), ALL_FILES);
    assert_eq!(count!(find_files(&dir, true, IgnoredDirNames { dir_names: &["AbC"], case: Case::Insensitive })), ALL_FILES - ALL_NESTED_FILES);

    assert_eq!(count!(find_files(&dir, true, SomeFileExts { file_exts: &["MD"], case: Case::Sensitive, files_without_extension: false })), 0);
    assert_eq!(
        count!(find_files(&dir, true, SomeFileExts { file_exts: &["MD"], case: Case::Insensitive, files_without_extension: false })),
        MD_FILES,
    );
    assert_eq!(
        count!(find_files(&dir, true, SomeFileExts { file_exts: &[], case: Case::Insensitive, files_without_extension: true })),
        FILES_WITHOUT_EXT,
    );
    assert_eq!(
        count!(find_files(&dir, true, SomeFileExts { file_exts: &[], case: Case::Sensitive, files_without_extension: true })),
        FILES_WITHOUT_EXT,
    );

    assert_eq!(count!(find_files(&dir, true, SomeFileNames { names: &["no-ext"], case: Case::Sensitive })), 1);
    assert_eq!(count!(find_files(&dir, true, SomeFileNames { names: &["NO-EXT"], case: Case::Sensitive })), 0);
    assert_eq!(count!(find_files(&dir, true, SomeFileNames { names: &["NO-EXT"], case: Case::Insensitive })), 1);

    assert_eq!(
        count!(find_files(&dir, true, IgnoredFileExts { file_exts: &["MD"], case: Case::Sensitive, files_without_extension: false })),
        ALL_FILES,
    );
    assert_eq!(
        count!(find_files(&dir, true, IgnoredFileExts { file_exts: &["MD"], case: Case::Insensitive, files_without_extension: false })),
        ALL_FILES - MD_FILES,
    );
    assert_eq!(
        count!(find_files(&dir, true, IgnoredFileExts { file_exts: &["MD"], case: Case::Sensitive, files_without_extension: true })),
        ALL_FILES - FILES_WITHOUT_EXT,
    );
    assert_eq!(
        count!(find_files(&dir, true, IgnoredFileExts { file_exts: &["MD"], case: Case::Insensitive, files_without_extension: true })),
        ALL_FILES - MD_FILES - FILES_WITHOUT_EXT,
    );

    assert_eq!(count!(find_files(&dir, true, IgnoredFileNames { file_names: &["SYMLINK"], case: Case::Sensitive })), ALL_FILES);
    assert_eq!(count!(find_files(&dir, true, IgnoredFileNames { file_names: &["symlink.ext"], case: Case::Sensitive })), ALL_FILES - 1);
    assert_eq!(count!(find_files(&dir, true, IgnoredFileNames { file_names: &["SYMLINK"], case: Case::Insensitive })), ALL_FILES - 1);

    assert_eq!(count!(find_files(&dir, true, SymlinkFiles)), SYMLINK_FILES);
    assert_eq!(count!(find_files(&dir, true, NonSymlinkFiles)), ALL_FILES - SYMLINK_FILES);

    let filters = &[
        SomeFileExts { file_exts: &[], case: Case::Sensitive, files_without_extension: true },
        SymlinkFiles,
    ];
    assert_eq!(count!(find_files(&dir, true, All { filters })), 1);

    assert_eq!(count!(FileDiscovery::make(&dir, true, AllPaths, Some(0))), ALL_FILES - ALL_NESTED_FILES);
    assert_eq!(count!(FileDiscovery::make(&dir, true, AllPaths, None)), ALL_FILES);
    assert_eq!(count!(FileDiscovery::make(&dir, true, AllPaths, Some(1))), ALL_FILES - LEVEL_2_NESTED_FILES);
    assert_eq!(count!(FileDiscovery::make(&dir, true, AllPaths, Some(2))), ALL_FILES);

    Ok(())
}
