/*
 * FileOperation04DeleteTest class.
 *
 * Copyright (C) 2007 SATOH Takayuki All Rights Reserved.
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package ts.util.file;

import ts.tester.function.FunctionTester;
import ts.tester.function.print.*;
import java.io.*;
import java.util.*;

/**
 * {@link ts.util.file.FileOperation04Delete FileOperation04Delete}クラスの機能試験クラス。
 *
 * @author  佐藤隆之.
 * @version $Revision: 1.1.1.1 $, $Date: 2010-10-16 00:03:46 $
 */
public class FileOperation04DeleteTest extends FunctionTester
{
  public static void main(String[] args)
  {
    try {
      run(FileOperation04DeleteTest.class, (args.length == 0) ? null : args[0]);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  final File WORKDIR = new File("test/data/ts/util/file/FileOperation");
  File[] DIRS = new File[6];
  File[] FILES = new File[10];

  protected void preInvocation(String method)
  {
    WORKDIR.mkdirs();
    DIRS[0] = new File(WORKDIR, "DIRS0");
    DIRS[1] = new File(DIRS[0], "DIRS1");
    DIRS[2] = new File(DIRS[0], "DIRS2");
    DIRS[3] = new File(DIRS[1], "DIRS3");
    DIRS[4] = new File(DIRS[2], "DIRS4");
    DIRS[5] = new File(DIRS[2], "DIRS5");
    FILES[0] = new File(DIRS[0], "FILES0");
    FILES[1] = new File(DIRS[1], "FILES1");
    FILES[2] = new File(DIRS[2], "FILES2");
    FILES[3] = new File(DIRS[3], "FILES3");
    FILES[4] = new File(DIRS[4], "FILES4");
    FILES[5] = new File(DIRS[0], "FILES5");
    FILES[6] = new File(DIRS[1], "FILES6");
    FILES[7] = new File(DIRS[2], "FILES7");
    FILES[8] = new File(DIRS[3], "FILES8");
    FILES[9] = new File(DIRS[4], "FILES9");
    try {
      for (File d : DIRS) d.mkdirs();
      for (File f : FILES) f.createNewFile();
    } catch (Exception e) {}

    /*
       DIRS[0]
        +- DIRS[1]
          +- DIRS[3]
            +- FILES[3]
            +- FILES[8]
          +- FILES[1]
          +- FILES[6]
        +- DIRS[2]
          +- DIRS[4]
            +- FILES[4]
            +- FILES[9]
          +- DIRS[5]
          +- FILES[2]
          +- FILES[7]
        +- FILES[0]
        +- FILES[5]
    */
  }

  protected void postInvocation(String method)
  {
    try {
      FileOperation.deleteRecursive(WORKDIR);
    } catch (Exception e) {}
  }

  /* -- test case -- */

  public void delete_file()
  {
    MSG("通常のファイルを削除。");

    TRUE(FILES[3].exists());

    try {
      FileOperation.delete(FILES[3]);
    } catch (Exception e) {
      NG(e);
    }

    FALSE(FILES[3].exists());
  }

  public void delete_file_01()
  {
    MSG("空のディレクトリを削除。");

    TRUE(DIRS[5].exists());

    try {
      FileOperation.delete(DIRS[5]);
    } catch (Exception e) {
      NG(e);
    }

    FALSE(DIRS[5].exists());
  }

  public void delete_file_02()
  {
    MSG("空でないディレクトリを削除しようとした場合。");

    TRUE(DIRS[4].exists());
    TRUE(FILES[4].exists());
    TRUE(FILES[9].exists());

    try {
      FileOperation.delete(DIRS[4]);
    } catch (DirectoryNotEmptyException e) {
      EQUAL(e.getPath(), DIRS[4].getPath());
      NULL(e.getMessage());
    } catch (Exception e) {
      NG(e);
    }

    TRUE(DIRS[4].exists());
    TRUE(FILES[4].exists());
    TRUE(FILES[9].exists());
  }

  public void delete_file_03()
  {
    MSG("存在しないファイルを削除しようとした場合。");

    File aFile = new File(WORKDIR, "aaa");

    FALSE(aFile.exists());

    try {
      FileOperation.delete(aFile);
      NG();
    } catch (FileNotFoundException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    FALSE(aFile.exists());
  }

  public void delete_file_04()
  {
    MSG("引数がヌルの場合。");

    try {
      FileOperation.delete(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void delete_file_05()
  {
    MSG("共有ロック中のファイルを削除しようとした場合。");

    try {
      FileOperationTest.lockFile("shared", FILES[3]);
      Thread.sleep(1000);
    } catch (Exception e) {
      NG(e);
    }

    try {
      FileOperation.delete(FILES[3]);
      Thread.sleep(1000);
      NG();
    } catch (IOException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    } finally {
      FileOperationTest.releaseLock();
    }

    TRUE(FILES[3].exists());
  }

  public void delete_file_06()
  {
    MSG("排他ロック中のファイルを削除しようとした場合。");

    try {
      FileOperationTest.lockFile("exclusive", FILES[2]);
      Thread.sleep(1000);
    } catch (Exception e) {
      NG(e);
    }

    try {
      FileOperation.delete(FILES[2]);
      Thread.sleep(1000);
      NG();
    } catch (IOException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    } finally {
      FileOperationTest.releaseLock();
    }

    TRUE(FILES[2].exists());
  }

  public void delete_file_filter()
  {
    MSG("フィルタに該当するファイルの削除。");

    FileFilter filter = new FileNameRegexFilter(".*3");

    for (File d : DIRS) TRUE(d.exists()); 
    for (File f : FILES) TRUE(f.exists()); 
    try {
      FileOperation.delete(FILES[3], filter);
    } catch (Exception e) {
      NG(e);
    }

    for (File d : DIRS) TRUE(d.exists()); 
    for (File f : FILES) if (! f.equals(FILES[3])) TRUE(f.exists()); 
    FALSE(FILES[3].exists());
  }

  public void delete_file_filter_01()
  {
    MSG("フィルタに該当するファイルが存在しなかった場合。");

    FileFilter filter = new FileNameRegexFilter(".*X");

    for (File d : DIRS) TRUE(d.exists()); 
    for (File f : FILES) TRUE(f.exists()); 
    try {
      FileOperation.delete(FILES[3], filter);
    } catch (Exception e) {
      NG(e);
    }
    for (File d : DIRS) TRUE(d.exists()); 
    for (File f : FILES) TRUE(f.exists()); 
  }

  public void delete_file_filter_02()
  {
    MSG("空でないディレクトリを削除しようとした場合。");

    TRUE(DIRS[3].exists());
    TRUE(FILES[3].exists());
    TRUE(FILES[8].exists());

    try {
      FileOperation.delete(DIRS[3], new FileTypeFilter(FileType.Directory));
      NG();
    } catch (DirectoryNotEmptyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    TRUE(DIRS[3].exists());
    TRUE(FILES[3].exists());
    TRUE(FILES[8].exists());
  }

  public void delete_file_filter_03()
  {
    MSG("存在しないファイルを削除しようとした場合。");

    File file = new File(WORKDIR, "aaa");

    FALSE(file.exists());

    try {
      FileOperation.delete(file, new FileNameRegexFilter("aaa"));
      NG();
    } catch (FileNotFoundException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

  }

  public void delete_file_filter_04()
  {
    MSG("引数がヌルの場合。");

    try {
      FileOperation.delete(null, new FileTypeFilter(FileType.File));
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      FileOperation.delete(FILES[4], (FileFilter) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void delete_file_filter_05()
  {
    MSG("共有ロック中のファイルを削除しようとした場合。");

    TRUE(FILES[4].exists());

    try {
      FileOperationTest.lockFile("shared", FILES[4]);
      Thread.sleep(1000);
    } catch (Exception e) {
      NG(e);
    }

    try {
      FileOperation.delete(FILES[4], new FileTypeFilter(FileType.File));
      Thread.sleep(1000);
      NG();
    } catch (IOException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    } finally {
      FileOperationTest.releaseLock();
    }

    TRUE(FILES[4].exists());
  }

  public void delete_file_filter_06()
  {
    MSG("排他ロック中のファイルを削除しようとした場合。");

    TRUE(FILES[4].exists());

    try {
      FileOperationTest.lockFile("exclusive", FILES[4]);
      Thread.sleep(1000);
    } catch (Exception e) {
      NG(e);
    }

    try {
      FileOperation.delete(FILES[4], new FileTypeFilter(FileType.File));
      Thread.sleep(1000);
      NG();
    } catch (IOException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    } finally {
      FileOperationTest.releaseLock();
    }

    TRUE(FILES[4].exists());
  }

  public void deleteRecursive()
  {
    MSG("ディレクトリを削除。");

    for (File d : DIRS) TRUE(d.exists());
    for (File f : FILES) TRUE(f.exists());

    try {
      FileOperation.deleteRecursive(DIRS[0]);
    } catch (Exception e) {
      NG(e);
    }

    for (File d : DIRS) FALSE(d.exists());
    for (File f : FILES) FALSE(f.exists());
  }

  public void deleteRecursive_01()
  {
    MSG("引数に通常のファイルを指定。");

    TRUE(FILES[4].exists());

    try {
      FileOperation.deleteRecursive(FILES[4]);
    } catch (Exception e) {
      e.printStackTrace();
      NG(e);
    }

    FALSE(FILES[4].exists());
  }

  public void deleteRecursive_02()
  {
    MSG("存在しないファイルを削除しようとした場合。");

    File file = new File(WORKDIR, "xxx");

    try {
      FileOperation.deleteRecursive(file);
      NG();
    } catch (FileNotFoundException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void deleteRecursive_03()
  {
    MSG("引数がヌルの場合。");

    try {
      FileOperation.deleteRecursive(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void deleteRecursive_04()
  {
    MSG("共有ロック中のファイルを削除しようとした場合。");

    try {
      FileOperationTest.lockFile("shared", FILES[4]);
      Thread.sleep(1000);
    } catch (Exception e) {
      NG(e);
    }

    try {
      FileOperation.deleteRecursive(DIRS[4]);
      Thread.sleep(1000);
      NG();
    } catch (IOException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    } finally {
      FileOperationTest.releaseLock();
    }

    TRUE(FILES[4].exists());
  }

  public void deleteRecursive_05()
  {
    MSG("排他ロック中のファイルを削除しようとした場合。");

    for (File d : DIRS) TRUE(d.exists());
    for (File f : FILES) TRUE(f.exists());

    try {
      FileOperationTest.lockFile("exclusive", FILES[9]);
      Thread.sleep(1000);
    } catch (Exception e) {
      NG(e);
    }

    try {
      FileOperation.deleteRecursive(DIRS[0]);
      Thread.sleep(1000);
      NG();
    } catch (IOException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    } finally {
      FileOperationTest.releaseLock();
    }

    for (File d : DIRS) TRUE(d.exists());
    for (File f : FILES) TRUE(f.exists());
  }

  public void deleteRecursive_file_filter()
  {
    MSG("フィルタに該当するファイルの削除。");

    for (File d : DIRS) TRUE(d.exists());
    for (File f : FILES) TRUE(f.exists());

    try {
      FileFilterGroupAnd filter = new FileFilterGroupAnd();
      filter.addFilter(new FileNameRegexFilter(".*[246].*"));

      FileOperation.deleteRecursive(DIRS[0], filter);
    } catch (Exception e) {
      NG(e);
    }

    TRUE(DIRS[0].exists());
    TRUE(DIRS[1].exists());
    TRUE(DIRS[3].exists());
    TRUE(FILES[3].exists());
    TRUE(FILES[8].exists());
    TRUE(FILES[1].exists());
    FALSE(FILES[6].exists());
    FALSE(DIRS[2].exists());
    FALSE(DIRS[4].exists());
    FALSE(FILES[4].exists());
    FALSE(FILES[9].exists());
    FALSE(DIRS[5].exists());
    FALSE(FILES[2].exists());
    FALSE(FILES[7].exists());
    TRUE(FILES[0].exists());
    TRUE(FILES[5].exists());
  }

  public void deleteRecursive_file_filter_01()
  {
    MSG("フィルタに該当するファイルが存在しなかった場合。");

    for (File d : DIRS) TRUE(d.exists());
    for (File f : FILES) TRUE(f.exists());

    try {
      FileFilterGroupAnd filter = new FileFilterGroupAnd();
      filter.addFilter(new FileNameRegexFilter("xxx"));

      FileOperation.deleteRecursive(DIRS[0], filter);
    } catch (FileNotFoundException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    for (File d : DIRS) TRUE(d.exists());
    for (File f : FILES) TRUE(f.exists());
  }

  public void deleteRecursive_file_filter_02()
  {
    MSG("引数に通常のファイルを指定。");

    for (File d : DIRS) TRUE(d.exists());
    for (File f : FILES) TRUE(f.exists());

    try {
      FileFilterGroupAnd filter = new FileFilterGroupAnd();
      filter.addFilter(new FileNameRegexFilter("a*"));

      FileOperation.deleteRecursive(DIRS[0], filter);
    } catch (Exception e) {
      NG(e);
    }

    for (File d : DIRS) TRUE(d.exists());
    for (File f : FILES) TRUE(f.exists());
  }

  public void deleteRecursive_file_filter_03()
  {
    MSG("存在しないファイルを削除しようとした場合。");

    File file = new File(WORKDIR, "aaa");
    FALSE(file.exists());

    try {
      FileFilterGroupAnd filter = new FileFilterGroupAnd();
      filter.addFilter(new FileNameRegexFilter("a*"));

      FileOperation.deleteRecursive(file, filter);
      NG();
    } catch (FileNotFoundException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void deleteRecursive_file_filter_04()
  {
    MSG("引数がヌルの場合。");

    try {
      FileFilterGroupAnd filter = new FileFilterGroupAnd();
      filter.addFilter(new FileNameRegexFilter("xxx"));

      FileOperation.deleteRecursive(null, filter);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      FileOperation.deleteRecursive(DIRS[3], null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void deleteRecursive_file_filter_05()
  {
    MSG("指定されたディレクトリ以下の全てのファイルが削除対象の場合。");

    for (File d : DIRS) TRUE(d.exists());
    for (File f : DIRS) TRUE(f.exists());

    try {
      FileFilterGroupAnd filter = new FileFilterGroupAnd();
      filter.addFilter(new FileNameRegexFilter(".*"));

      FileOperation.deleteRecursive(DIRS[0], filter);
    } catch (Exception e) {
      e.printStackTrace();
      NG(e);
    }

    for (File d : DIRS) {OK(d.getPath()); FALSE(d.exists());}
    for (File f : FILES) {OK(f.getPath()); FALSE(f.exists());}
  }

  public void deleteRecursive_file_filter_06()
  {
    MSG("削除対象のファイルの中に共有ロックされたファイルがあった場合。");

    List<File> fL = null;
    try {
      fL = FileOperation.listRecursive(DIRS[1]);
    } catch (Exception e) {
      NG(e);
      return;
    }

    try {
      FileOperationTest.lockFile("shared", FILES[3]);
      Thread.sleep(1000);
    } catch (Exception e) {
      NG(e);
    }

    try {
      FileFilter filter = new FileTypeFilter(FileType.File);
      FileOperation.deleteRecursive(DIRS[1], filter);
    } catch (IOException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    } finally {
      FileOperationTest.releaseLock();
    }

    List<File> fL2 = null;
    try {
      fL2 = FileOperation.listRecursive(DIRS[1]);
    } catch (Exception e) {
      NG(e);
      return;
    }
   
    EQUAL(fL.size(), fL2.size());
    for (int i=0; i<fL.size(); i++) {
      EQUAL(fL.get(i), fL2.get(i));
    }
  }

  public void deleteRecursive_file_filter_07()
  {
    MSG("削除対象のファイルの中に排他ロックされたファイルがあった場合。");

    List<File> fL = null;
    try {
      fL = FileOperation.listRecursive(DIRS[1]);
    } catch (Exception e) {
      NG(e);
      return;
    }

    try {
      FileOperationTest.lockFile("exclusive", FILES[3]);
      Thread.sleep(1000);
    } catch (Exception e) {
      NG(e);
    }

    try {
      FileFilter filter = new FileTypeFilter(FileType.File);
      FileOperation.deleteRecursive(DIRS[1], filter);
    } catch (IOException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    } finally {
      FileOperationTest.releaseLock();
    }

    List<File> fL2 = null;
    try {
      fL2 = FileOperation.listRecursive(DIRS[1]);
    } catch (Exception e) {
      NG(e);
      return;
    }
   
    EQUAL(fL.size(), fL2.size());
    for (int i=0; i<fL.size(); i++) {
      EQUAL(fL.get(i), fL2.get(i));
    }
  }
}

