/*
 * DrFx - FxCop Report Translator and Visualizer.
 * Copyright (C) 2010 Sasa Yuan
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */



using NUnit.Framework;
using Sasa.QualityTools.DrFx.Console.Tests.Integration.Helpers;
using System;
using System.Collections.Generic;
using System.IO;

namespace Sasa.QualityTools.DrFx.Console.Tests.Integration
{
    [TestFixture]
    public class FileSystemSearcherTest
    {
        /// <summary>
        /// 作業ディレクトリにテスト用のファイル、ディレクトリを作成します。
        /// </summary>
        [TestFixtureSetUp]
        public void SetUpFixture()
        {
            SetUpHelper.Create("fsst.txt");
            SetUpHelper.Create("fsst/");
            SetUpHelper.Create("fsst/file1.txt");
            SetUpHelper.Create("fsst/file2.txt");
            SetUpHelper.Create("fsst/file3.xml");
            SetUpHelper.Create("fsst/dir1/");
            SetUpHelper.Create("fsst/dir1/file1.txt");
            SetUpHelper.Create("fsst/dir1/file2.xml");
            SetUpHelper.Create("fsst/dir1/file3.xml");
            SetUpHelper.Create("fsst/dir2/");
            SetUpHelper.Create("fsst/dir2/dir2_1/");
            SetUpHelper.Create("fsst/dir2/dir2_1/file1.txt");
            SetUpHelper.Create("fsst/dir2/dir2_1/file2.xml");
            SetUpHelper.Create("fsst/dir2/dir2_2/");
            SetUpHelper.Create("fsst/dir2/dir2_2/file1");
            SetUpHelper.Create("fsst/dir2/dir2_3/");
            SetUpHelper.Create("fsst/dir2/dir2_3/file1.txt");
            SetUpHelper.Create("fsst/dir2/dir2_4/");
            SetUpHelper.Create("fsst/dir3/");
        }

        /// <summary>
        /// SetUpFixture メソッドが作成したテスト用ファイル、ディレクトリを削除します。
        /// </summary>
        [TestFixtureTearDown]
        public void TearDownFixture()
        {
            Directory.Delete("fsst", true);
            File.Delete("fsst.txt");
        }

        /// <summary>
        /// ディレクトリ直接指定、ワイルドカード指定の各パターンでディレクトリ検索が正しく行えることを確認します。
        /// </summary>
        /// <param name="pattern">ディレクトリ検索パターン。</param>
        /// <returns>検索して得られたディレクトリパスの配列。</returns>
        [Test]
        [TestCaseSource(typeof(SearchDirectoriesTestCaseGenerator), "Generate")]
        public string[] TestSearchDirectories(string pattern)
        {
            return FileSystemSearcher.SearchDirectories(pattern);
        }

        /// <summary>
        /// ファイル直接指定、ワイルドカード指定の各パターンでファイル検索が正しく行えることを確認します。
        /// </summary>
        /// <param name="pattern">ファイル検索パターン。</param>
        /// <returns>検索して得られたファイルパスの配列。</returns>
        [Test]
        [TestCaseSource(typeof(SearchFilesTestCaseGenerator), "Generate")]
        public string[] TestSearchFiles(string pattern)
        {
            return FileSystemSearcher.SearchFiles(pattern);
        }

        /// <summary>
        /// ファイル検索テストのテストケースデータ生成クラスです。
        /// </summary>
        private class SearchFilesTestCaseGenerator
        {
            /// <summary>
            /// テストケースデータのコレクションを生成します。
            /// </summary>
            /// <returns>生成したテストケースデータのコレクション。</returns>
            private IEnumerable<TestCaseData> Generate()
            {
                yield return new TestCaseData("foo")
                    .Returns(new string[] { })
                    .SetDescription("存在しないディレクトリを指定した場合は空の検索結果が返されることをテストします。");

                yield return new TestCaseData("fsst.txt")
                    .Returns(new string[] { "fsst.txt" })
                    .SetDescription("ファイルを指定した場合はそのファイルのみが検索結果として返されることをテストします。");

                yield return new TestCaseData("fsst")
                    .Returns(new string[] { })
                    .SetDescription("ディレクトリを指定した場合は空の検索結果が返されることをテストします。");

                yield return new TestCaseData(@"fsst\*")
                    .Returns(new string[] { @"fsst\file1.txt", @"fsst\file2.txt", @"fsst\file3.xml" })
                    .SetDescription("ディレクトリ内のファイルをワイルドカード '*' で検索できることをテストします。");

                yield return new TestCaseData(@"fsst\*.txt")
                    .Returns(new string[] { @"fsst\file1.txt", @"fsst\file2.txt" })
                    .SetDescription("ディレクトリ内のファイルを '*.txt' で検索できることをテストします。");

                yield return new TestCaseData(@"fsst\dir1")
                    .Returns(new string[] { })
                    .SetDescription("ネストされたディレクトリを指定すると空の検索結果が返されることをテストします。");

                yield return new TestCaseData(@"fsst\dir1\file?.xml")
                    .Returns(new string[] { @"fsst\dir1\file2.xml", @"fsst\dir1\file3.xml" })
                    .SetDescription("ディレクトリ内のファイルを 'file?.txt' で検索できることをテストします。");

                yield return new TestCaseData(@"fsst\dir1\file1.txt")
                    .Returns(new string[] { @"fsst\dir1\file1.txt" })
                    .SetDescription("サブディレクトリ内のファイルを指定した場合はそのファイルのみが検索結果として返されることをテストします。");

                yield return new TestCaseData(@"fsst\*\dir2_1\*")
                    .Returns(new string[] { @"fsst\dir2\dir2_1\file1.txt", @"fsst\dir2\dir2_1\file2.xml" })
                    .SetDescription("ネストされたディレクトリ内のファイルを検索する際に検索パスの途中にワイルドカードが使えることをテストします。");

                yield return new TestCaseData(@"fsst\*\*\*")
                    .Returns(new string[] { @"fsst\dir2\dir2_1\file1.txt", @"fsst\dir2\dir2_1\file2.xml", @"fsst\dir2\dir2_2\file1", @"fsst\dir2\dir2_3\file1.txt" })
                    .SetDescription("ネストされたディレクトリ内のファイルを検索する際に複数のワイルドカードを連続して使えることをテストします。");

                yield return new TestCaseData(@"fsst\*\dir2_4")
                    .Returns(new string[] { })
                    .SetDescription("ファイルを含まないディレクトリが検索対象となった場合は空の検索結果が返されることをテストします。");

                yield return new TestCaseData(Directory.GetCurrentDirectory() + @"\fsst.txt")
                    .Returns(new string[] { Directory.GetCurrentDirectory() + @"\fsst.txt" })
                    .SetDescription("フルパス指定でファイルを検索できることをテストします。");

                yield return new TestCaseData(Directory.GetCurrentDirectory() + @"\fsst\dir1\*.xml")
                    .Returns(new string[] { Directory.GetCurrentDirectory() + @"\fsst\dir1\file2.xml", Directory.GetCurrentDirectory() + @"\fsst\dir1\file3.xml" })
                    .SetDescription("フルパス指定検索の際にワイルドカードが使えることをテストします。");
            }
        }

        /// <summary>
        /// ディレクトリ検索テストのテストケースデータ生成クラスです。
        /// </summary>
        private class SearchDirectoriesTestCaseGenerator
        {
            /// <summary>
            /// テストケースデータのコレクションを生成します。
            /// </summary>
            /// <returns>生成したテストケースデータのコレクション。</returns>
            private IEnumerable<TestCaseData> Generate()
            {
                yield return new TestCaseData("foo")
                    .Returns(new string[] { })
                    .SetDescription("存在しないディレクトリを指定した場合は空の検索結果が返されることをテストします。");

                yield return new TestCaseData("fsst.txt")
                    .Returns(new string[] { })
                    .SetDescription("ファイルを指定した場合は空の検索結果が返されることをテストします。");

                yield return new TestCaseData("fsst")
                    .Returns(new string[] { @"fsst" })
                    .SetDescription("ディレクトリを指定した場合はそのディレクトリが検索結果として返されることをテストします。");

                yield return new TestCaseData(@"fsst\*")
                    .Returns(new string[] { @"fsst\dir1", @"fsst\dir2", @"fsst\dir3" })
                    .SetDescription("ワイルドカードを指定した場合はワイルドカードに一致するディレクトリが検索結果として返されることをテストします。");

                yield return new TestCaseData(@"fsst\*\dir2_1")
                    .Returns(new string[] { @"fsst\dir2\dir2_1" })
                    .SetDescription("ネストされたディレクトリを検索する際に検索パスの途中にワイルドカードが使えることをテストします。");

                yield return new TestCaseData(@"fsst\*\*")
                    .Returns(new string[] { @"fsst\dir2\dir2_1", @"fsst\dir2\dir2_2", @"fsst\dir2\dir2_3", @"fsst\dir2\dir2_4" })
                    .SetDescription("ネストされたディレクトリを検索する際に複数のワイルドカードを連続して使えることをテストします。");

                yield return new TestCaseData(Directory.GetCurrentDirectory() + @"\fsst")
                    .Returns(new string[] { Directory.GetCurrentDirectory() + @"\fsst" })
                    .SetDescription("フルパス指定でディレクトリを検索できることをテストします。");

                yield return new TestCaseData(Directory.GetCurrentDirectory() + @"\fsst\*")
                    .Returns(new string[] { Directory.GetCurrentDirectory() + @"\fsst\dir1", Directory.GetCurrentDirectory() + @"\fsst\dir2", Directory.GetCurrentDirectory() + @"\fsst\dir3" })
                    .SetDescription("フルパス指定検索の際にワイルドカードが使えることをテストします。");
            }
        }
    }
}
