/*
 * CountDownTest 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;

import ts.tester.function.coverage.FunctionTester;
import ts.tester.function.ObjectInspector;
import ts.tester.function.print.*;

/**
 * <code>CountDown</code>クラスの機能試験クラス。
 *
 * @author  佐藤隆之. 
 * @version $Revision: 1.2 $, $Date: 2011-08-02 15:50:39 $
 */
public class CountDownTest extends FunctionTester
{
  public static void main(String[] args)
  {
    try {
      PrinterGroup group = new PrinterGroup();
      group.addPrinter(new ConsolePrinter());
      group.addPrinter(new HtmlPrinter("SATOH Takayuki"));
      setPrinter(group);

      run(CountDownTest.class, (args.length == 0) ? null : args[0]);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  private ObjectInspector oi_ = new ObjectInspector(this);

  protected void preTesting()
  {
    MSG("CountDownクラスの機能試験を実行する。");
  }

  protected void preInvocation(String methodName)
  {
    oi_.expect("value_", 0L);
    oi_.expect("limit_", 0L);
    oi_.expect("serialVersionUID", CountDown.serialVersionUID);
  }

  /* -- text case -- */

  public void constructor_init()
  {
    MSG("初期値を引数にとるコンストラクタの確認。");

    MSG("カウンタの初期値にゼロを設定した場合。");
    CountDown cdw0 = new CountDown(0L);
    oi_.expect("limit_", 0L);
    oi_.inspect(cdw0);

    MSG("カウンタの初期値に下限値よりも大きい値を設定した場合。");
    CountDown cdw1 = new CountDown(10L);
    oi_.expect("value_", 10L);
    oi_.expect("limit_", 0L);
    oi_.inspect(cdw1);

    MSG("カウンタの初期値に下限値よりも小さい値を設定した場合。");
    CountDown cdw2 = new CountDown(-10L);
    oi_.expect("value_", -10L);
    oi_.expect("limit_", 0L);
    oi_.inspect(cdw2);
  }

  public void constructor_init_limit()
  {
    MSG("初期値と下限値を引数にとるコンストラクタの確認。");

    MSG("初期値と下限値に同じ値を設定した場合。");
    CountDown cdw0 = new CountDown(0L, 0L);
    oi_.expect("value_", 0L);
    oi_.expect("limit_", 0L);
    oi_.inspect(cdw0);

    MSG("初期値に下限値よりも大きい値を設定した場合。");
    CountDown cdw1 = new CountDown(10L, -10L);
    oi_.expect("value_", 10L);
    oi_.expect("limit_", -10L);
    oi_.inspect(cdw1);

    MSG("初期値に下限値よりも小さい値を設定した場合。");
    CountDown cdw2 = new CountDown(-10L, 10L);
    oi_.expect("value_", -10L);
    oi_.expect("limit_", 10L);
    oi_.inspect(cdw2);
  }

  public void currentValue()
  {
    MSG("現在の値を取得するメソッドの確認。");

    MSG("初期値にゼロを設定した場合。");
    CountDown cdw = new CountDown(0L);
    oi_.expect("value_", cdw.currentValue());
    oi_.expect("limit_", 0L);
    oi_.inspect(cdw);

    MSG("初期値に下限値よりも大きい値を設定した場合。");
    cdw = new CountDown(10L);
    oi_.expect("value_", cdw.currentValue());
    oi_.expect("limit_", 0L);
    oi_.inspect(cdw);

    MSG("初期値に下限値よりも小さい値を設定した場合。");
    cdw = new CountDown(-10L);
    oi_.expect("value_", cdw.currentValue());
    oi_.expect("limit_", 0L);
    oi_.inspect(cdw);
  }

  public void limitValue()
  {
    MSG("下限値を取得するメソッドの確認。");

    MSG("初期値と下限値に同じ値（ゼロ）を設定した場合。");
    CountDown cdw = new CountDown(0L, 0L);
    oi_.expect("value_", cdw.currentValue());
    oi_.expect("limit_", cdw.limitValue());
    oi_.inspect(cdw);

    MSG("初期値に下限値よりも大きい値を設定した場合。");
    cdw = new CountDown(10L, 5L);
    oi_.expect("value_", cdw.currentValue());
    oi_.expect("limit_", cdw.limitValue());
    oi_.inspect(cdw);

    MSG("初期値に下限値よりも小さい値を設定した場合。");
    cdw = new CountDown(-10L, -5L);
    oi_.expect("value_", cdw.currentValue());
    oi_.expect("limit_", cdw.limitValue());
    oi_.inspect(cdw);
  }

  public void isReached()
  {
    MSG("カウンタの値が下限値に至ったかどうかを判定するメソッドの確認。");

    CountDown cdw;

    MSG("初期値と下限値に同じ値（ゼロ）を設定した場合。");
    cdw = new CountDown(0L, 0L);
    TRUE(cdw.isReached());

    MSG("初期値に下限値よりも大きい値を設定した場合。");
    cdw = new CountDown(10L, 5L);
    FALSE(cdw.isReached());

    MSG("初期値に下限値よりも小さい値を設定した場合。");
    cdw = new CountDown(-10L, -5L);
    TRUE(cdw.isReached());
  }

  public void decrement()
  {
    MSG("カウンタの値を減じるメソッドの確認。");

    CountDown cdw;

    cdw = new CountDown(3L);
    EQUAL(cdw.currentValue(), 3L);
    EQUAL(cdw.limitValue(), 0L);

    EQUAL(cdw.decrement(), 2L);
    EQUAL(cdw.currentValue(), 2L);
    FALSE(cdw.isReached());

    EQUAL(cdw.decrement(), 1L);
    EQUAL(cdw.decrement(), 0L);
    EQUAL(cdw.currentValue(), 0L);
    TRUE(cdw.isReached());

    try {
      cdw.decrement();
      NG();
    }
    catch (OutOfRangeException e) {
      OK(e);
    }
  }

  public void test_of_useful()
  {
    MSG("実際の使用を模擬した動作確認。");

    MSG("初期値10、下限値0の場合。");
    int i=10;
    for (CountDown cdw = new CountDown(10); !cdw.isReached(); cdw.decrement()) {
      EQUAL(cdw.currentValue(), i);
      i--;
    }
    EQUAL(i, 0);

    MSG("初期値10、下限値12の場合。");
    i = 10;
    for (CountDown c = new CountDown(10, 12); !c.isReached(); c.decrement()) {
      EQUAL(c.currentValue(), i);
      i--;
    }
    EQUAL(i, 10);
  }

  public void synchronizedCountDown_init()
  {
    MSG("初期値を引数にとるスレッドセーフなオブジェクトの作成メソッドの確認。");

    int i=0;
    CountDown cdw = CountDown.synchronizedCountDown(5);
    EQUAL(cdw.currentValue(), 5);
    EQUAL(cdw.limitValue(), 0);
    while (!cdw.isReached()) {
      EQUAL(cdw.currentValue(), 5-i);
      cdw.decrement();
      i++;
    }
    EQUAL(i, 5);
    EQUAL(cdw.currentValue(), 0);

    i=0;
    cdw = CountDown.synchronizedCountDown(-5);
    EQUAL(cdw.currentValue(), -5);
    EQUAL(cdw.limitValue(), 0);
    while (!cdw.isReached()) {
      EQUAL(cdw.currentValue(), -5-i);
      cdw.decrement();
      i++;
    }
    EQUAL(i, 0);
    EQUAL(cdw.currentValue(), -5);
  }

  public void synchronizedCountDown_init_limit()
  {
    MSG("初期値と下限値を引数にとるスレッドセーフなオブジェクトの作成メソッドの確認。");

    int i=0;
    CountDown cdw = CountDown.synchronizedCountDown(5, -5);
    EQUAL(cdw.currentValue(), 5);
    EQUAL(cdw.limitValue(), -5);
    while (!cdw.isReached()) {
      EQUAL(cdw.currentValue(), 5-i);
      cdw.decrement();
      i++;
    }
    EQUAL(i, 10);
    EQUAL(cdw.currentValue(), -5);

    i=0;
    cdw = CountDown.synchronizedCountDown(-5, 5);
    EQUAL(cdw.currentValue(), -5);
    EQUAL(cdw.limitValue(), 5);
    while (!cdw.isReached()) {
      EQUAL(cdw.currentValue(), -5-i);
      cdw.decrement();
      i++;
    }
    EQUAL(i, 0);
    EQUAL(cdw.currentValue(), -5);
  }

  public void synchronizedCountDown_CountDown()
  {
    MSG("CountDownオブジェクトを引数にとるスレッドセーフなオブジェクトの作成メソッドの確認。");

    int i=0;
    CountDown cdw = CountDown.synchronizedCountDown(new CountDown(5, -5));
    EQUAL(cdw.currentValue(), 5);
    EQUAL(cdw.limitValue(), -5);
    while (!cdw.isReached()) {
      EQUAL(cdw.currentValue(), 5-i);
      cdw.decrement();
      i++;
    }
    EQUAL(i, 10);
    EQUAL(cdw.currentValue(), -5);

    i=0;
    cdw = CountDown.synchronizedCountDown(new CountDown(-5, 5));
    EQUAL(cdw.currentValue(), -5);
    EQUAL(cdw.limitValue(), 5);
    while (!cdw.isReached()) {
      EQUAL(cdw.currentValue(), -5-i);
      cdw.decrement();
      i++;
    }
    EQUAL(i, 0);
    EQUAL(cdw.currentValue(), -5);
  }

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

    try {
      CountDown cdw = CountDown.synchronizedCountDown(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }
}
