/*
 * CountUpTest 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.print.*;
import ts.tester.function.ObjectInspector;

/**
 * <code>CountUp</code>クラスの機能試験クラス。
 *
 * @author  佐藤隆之. 
 * @version $Revision: 1.2 $, $Date: 2011-08-02 15:50:39 $
 */
public class CountUpTest 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(CountUpTest.class, (args.length == 0) ? null : args[0]);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  private ObjectInspector oi_ = new ObjectInspector(this);

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

  @Override
  protected void preInvocation(String methodName)
  {
    oi_.expect("value_", 0L);
    oi_.expect("limit_", Long.MAX_VALUE);
    oi_.expect("serialVersionUID", CountUp.serialVersionUID);
  }

  /* -- text case -- */

  public void constructor()
  {
    MSG("デフォルトコンストラクタで生成した場合。");
    CountUp c0 = new CountUp();
    oi_.inspect(c0);
  }

  public void constructor_limit()
  {
    MSG("上限値にゼロを設定した場合");
    CountUp c0 = new CountUp(0L);
    oi_.expect("limit_", 0L);
    oi_.inspect(c0);

    MSG("上限値に初期値より大きい値を設定した場合");
    CountUp c1 = new CountUp(10L);
    oi_.expect("limit_", 10L);
    oi_.inspect(c1);

    MSG("上限値に初期値より小さい値を設定した場合");
    CountUp c2 = new CountUp(-10L);
    oi_.expect("limit_", -10L);
    oi_.inspect(c2);
  }

  public void constructor_init_limit()
  {
    MSG("初期値と上限値に同じ値（ゼロ）を指定した場合");
    CountUp c0 = new CountUp(0L, 0L);
    oi_.expect("value_", 0L);
    oi_.expect("limit_", 0L);
    oi_.inspect(c0);

    MSG("初期値＞上限値の場合");
    CountUp c1 = new CountUp(10L, -10L);
    oi_.expect("value_", 10L);
    oi_.expect("limit_", -10L);
    oi_.inspect(c1);

    MSG("初期値＜上限値の場合");
    CountUp c2 = new CountUp(-10L, 10L);
    oi_.expect("value_", -10L);
    oi_.expect("limit_", 10L);
    oi_.inspect(c2);
  }

  public void currentValue_and_limitValue()
  {
    MSG("デフォルトコンストラクタの実行直後");
    CountUp c0 = new CountUp();
    oi_.expect("value_", c0.currentValue());
    oi_.expect("limit_", c0.limitValue());
    oi_.inspect(c0);

    MSG("初期値を引数にとるコンストラクタの実行直後");
    CountUp c1 = new CountUp(12L);
    oi_.expect("value_", c1.currentValue());
    oi_.expect("limit_", c1.limitValue());
    oi_.inspect(c1);

    MSG("初期値と上限値を引数にとるコンストラクタの実行直後(init < limit)");
    CountUp c2 = new CountUp(12L, 50L);
    oi_.expect("value_", c2.currentValue());
    oi_.expect("limit_", c2.limitValue());
    oi_.inspect(c2);

    MSG("初期値と上限値を引数にとるコンストラクタの実行直後(init > limit)");
    CountUp c3 = new CountUp(-12L, -50L);
    oi_.expect("value_", c3.currentValue());
    oi_.expect("limit_", c3.limitValue());
    oi_.inspect(c3);
  }

  public void isReached()
  {
    MSG("初期値と上限値に同じ値（ゼロ）を指定した場合");
    CountUp c0 = new CountUp(0, 0);
    TRUE(c0.isReached());

    MSG("初期値＜上限値の場合");
    CountUp c1 = new CountUp(4, 10);
    FALSE(c1.isReached());

    MSG("初期値＞上限値の場合");
    CountUp c2 = new CountUp(0, -4);
    TRUE(c2.isReached());
  }

  public void increment()
  {
    MSG("カウンタの値を増やすメソッドの確認。");

    CountUp c = new CountUp(3);
    EQUAL(c.currentValue(), 0);
    EQUAL(c.limitValue(), 3);
    FALSE(c.isReached());

    EQUAL(c.increment(), 1);
    EQUAL(c.currentValue(), 1);
    EQUAL(c.limitValue(), 3);
    FALSE(c.isReached());

    EQUAL(c.increment(), 2);
    EQUAL(c.increment(), 3);
    EQUAL(c.currentValue(), 3);
    TRUE(c.isReached());

    try {
      c.increment();
      NG();
    }
    catch (OutOfRangeException e) {
      OK(e);
    }
  }

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

    int i = 0;
    for (CountUp c = new CountUp(10); !c.isReached(); c.increment()) {
      EQUAL(c.currentValue(), i);
      i ++;
    }
    EQUAL(i, 10);

    i = 0;
    for (CountUp c = new CountUp(-3); !c.isReached(); c.increment()) {
      EQUAL(c.currentValue(), i);
      i ++;
    }
    EQUAL(i, 0);
  }

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

    long i = 0;
    CountUp c = CountUp.synchronizedCountUp();
    EQUAL(c.currentValue(), 0);
    EQUAL(c.limitValue(), Long.MAX_VALUE);
    while (!c.isReached()) {
      c.increment();
      i++;
      if (i == 10) break;
    }
    EQUAL(i, 10);
    EQUAL(c.currentValue(), 10);
  }

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

    int i = 0;
    CountUp c = CountUp.synchronizedCountUp(5);
    EQUAL(c.currentValue(), 0);
    EQUAL(c.limitValue(), 5);
    while (!c.isReached()) {
      EQUAL(c.currentValue(), i);
      c.increment();
      i++;
    }
    EQUAL(i, 5);
    EQUAL(c.currentValue(), 5);

    i = 0;
    c = CountUp.synchronizedCountUp(-5);
    EQUAL(c.currentValue(), 0);
    EQUAL(c.limitValue(), -5);
    while (!c.isReached()) {
      EQUAL(c.currentValue(), i);
      c.increment();
      i++;
    }
    EQUAL(i, 0);
    EQUAL(c.currentValue(), 0);
  }

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

    int i = 0;
    CountUp c = CountUp.synchronizedCountUp(4, 10);
    EQUAL(c.currentValue(), 4);
    EQUAL(c.limitValue(), 10);
    while (!c.isReached()) {
      EQUAL(c.currentValue(), i+4);
      c.increment();
      i++;
    }
    EQUAL(i, 6);
    EQUAL(c.currentValue(), 10);

    i = 0;
    c = CountUp.synchronizedCountUp(10, 4);
    EQUAL(c.currentValue(), 10);
    EQUAL(c.limitValue(), 4);
    while (!c.isReached()) {
      EQUAL(c.currentValue(), i);
      c.increment();
      i++;
    }
    EQUAL(i, 0);
    EQUAL(c.currentValue(), 10);
  }

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

    int i = 0;
    CountUp c = CountUp.synchronizedCountUp(new CountUp(4, 10));
    EQUAL(c.currentValue(), 4);
    EQUAL(c.limitValue(), 10);
    while (!c.isReached()) {
      EQUAL(c.currentValue(), i+4);
      c.increment();
      i++;
    }
    EQUAL(i, 6);
    EQUAL(c.currentValue(), 10);

    i = 0;
    c = CountUp.synchronizedCountUp(new CountUp(10, 4));
    EQUAL(c.currentValue(), 10);
    EQUAL(c.limitValue(), 4);
    while (!c.isReached()) {
      EQUAL(c.currentValue(), i);
      c.increment();
      i++;
    }
    EQUAL(i, 0);
    EQUAL(c.currentValue(), 10);
  }

  public void synchronizedCountUp_CountUp_1()
  {
    try {
      CountUp c = CountUp.synchronizedCountUp(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }
}
