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

  private ObjectInspector oi_ = new ObjectInspector(this);

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

  @Override
  protected void preInvocation(String methodName)
  {
    oi_.expect("value_", 0L);
    oi_.expect("minLimit_", Long.MIN_VALUE);
    oi_.expect("maxLimit_", Long.MAX_VALUE);
    oi_.expect("serialVersionUID", CountRotate.serialVersionUID);
  }

  /* -- test case -- */

  public void constructor()
  {
    MSG("デフォルトコンストラクタの確認。");

    CountRotate c0 = new CountRotate();
    oi_.inspect(c0);
  }

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

    CountRotate c0 = new CountRotate(0L);
    oi_.expect("value_", 0L);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), 0L);

    c0 = new CountRotate(10L);
    oi_.expect("value_", 10L);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), 10L);

    c0 = new CountRotate(Long.MAX_VALUE);
    oi_.expect("value_", Long.MAX_VALUE);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), Long.MAX_VALUE);

    c0 = new CountRotate(Long.MIN_VALUE);
    oi_.expect("value_", Long.MIN_VALUE);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), Long.MIN_VALUE);
  }

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

    CountRotate c0 = new CountRotate(0L, -10L, 10L);
    oi_.expect("value_", 0L);
    oi_.expect("minLimit_", -10L);
    oi_.expect("maxLimit_", 10L);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), 0L);

    c0 = new CountRotate(0L, Long.MIN_VALUE, Long.MAX_VALUE);
    oi_.expect("value_", 0L);
    oi_.expect("minLimit_", Long.MIN_VALUE);
    oi_.expect("maxLimit_", Long.MAX_VALUE);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), 0L);

    c0 = new CountRotate(10L, 0L, 100L);
    oi_.expect("value_", 10L);
    oi_.expect("minLimit_", 0L);
    oi_.expect("maxLimit_", 100L);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), 10L);

    c0 = new CountRotate(10L, 10L, 10L);
    oi_.expect("value_", 10L);
    oi_.expect("minLimit_", 10L);
    oi_.expect("maxLimit_", 10L);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), 10L);
  }

  public void constructor_init_min_max_0()
  {
    MSG("下限値と上限値の大小関係を逆に指定した場合。");

    CountRotate c0 = new CountRotate(0L, 10L, -10L);
    oi_.expect("value_", 0L);
    oi_.expect("minLimit_", -10L);
    oi_.expect("maxLimit_", 10L);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), 0L);

    c0 = new CountRotate(100L, 100L, -10L);
    oi_.expect("value_", 100L);
    oi_.expect("minLimit_", -100L);
    oi_.expect("maxLimit_", 100L);
    EQUAL(c0.currentValue(), 100L);
  }

  public void constructor_init_min_max_1()
  {
    MSG("初期値が下限値と上限値の範囲外にある場合。");

    CountRotate c0 = new CountRotate(20L, -10L, 10L);
    oi_.expect("value_", 10L);
    oi_.expect("minLimit_", -10L);
    oi_.expect("maxLimit_", 10L);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), 10L);

    c0 = new CountRotate(-20L, -10L, 10L);
    oi_.expect("value_", -10L);
    oi_.expect("minLimit_", -10L);
    oi_.expect("maxLimit_", 10L);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), -10L);

    c0 = new CountRotate(-20L, 10L, -10L);
    oi_.expect("value_", -10L);
    oi_.expect("minLimit_", -10L);
    oi_.expect("maxLimit_", 10L);
    oi_.inspect(c0);

    c0 = new CountRotate(20L, 10L, -10L);
    oi_.expect("value_", 10L);
    oi_.expect("minLimit_", -10L);
    oi_.expect("maxLimit_", 10L);
    oi_.inspect(c0);
    EQUAL(c0.currentValue(), 10L);
  }

  public void increment()
  {
    MSG("カウンタを加算するメソッドの確認。");

    CountRotate c0 = new CountRotate(0L, 0L, 5L);
    EQUAL(c0.currentValue(), 0L);

    EQUAL(c0.increment(), 1L);
    EQUAL(c0.currentValue(), 1L);

    EQUAL(c0.increment(), 2L);
    EQUAL(c0.currentValue(), 2L);

    EQUAL(c0.increment(), 3L);
    EQUAL(c0.currentValue(), 3L);

    EQUAL(c0.increment(), 4L);
    EQUAL(c0.currentValue(), 4L);

    EQUAL(c0.increment(), 5L);
    EQUAL(c0.currentValue(), 5L);

    EQUAL(c0.increment(), 0L);
    EQUAL(c0.currentValue(), 0L);

    EQUAL(c0.increment(), 1L);
    EQUAL(c0.currentValue(), 1L);

    EQUAL(c0.increment(), 2L);
    EQUAL(c0.currentValue(), 2L);

    EQUAL(c0.increment(), 3L);
    EQUAL(c0.currentValue(), 3L);

    EQUAL(c0.increment(), 4L);
    EQUAL(c0.currentValue(), 4L);

    EQUAL(c0.increment(), 5L);
    EQUAL(c0.currentValue(), 5L);

    EQUAL(c0.increment(), 0L);
    EQUAL(c0.currentValue(), 0L);

    EQUAL(c0.increment(), 1L);
    EQUAL(c0.currentValue(), 1L);
  }

  public void increment_0()
  {
    MSG("初期値、下限値、上限値が同じ値の場合。");

    CountRotate c0 = new CountRotate(10L, 10L, 10L);
    EQUAL(c0.currentValue(), 10L);

    EQUAL(c0.increment(), 10L);
    EQUAL(c0.currentValue(), 10L);

    EQUAL(c0.increment(), 10L);
    EQUAL(c0.currentValue(), 10L);

    EQUAL(c0.increment(), 10L);
    EQUAL(c0.currentValue(), 10L);

    EQUAL(c0.increment(), 10L);
    EQUAL(c0.currentValue(), 10L);
  }

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

    long i = 0;
    CountRotate c = CountRotate.synchronizedCountRotate();
    EQUAL(c.currentValue(), 0);
    while (i < 100) {
      EQUAL(c.currentValue(), i);
      i++;
      EQUAL(c.increment(), i);
    }
    EQUAL(i, 100);
    EQUAL(c.currentValue(), 100);
  }

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

    int i = 0;
    long l = Long.MAX_VALUE - 10L;
    CountRotate c = CountRotate.synchronizedCountRotate(l);
    EQUAL(c.currentValue(), l);
    while (l >= Long.MAX_VALUE - 10L || l < Long.MIN_VALUE + 10L) {
      EQUAL(c.currentValue(), l);
      l = (l == Long.MAX_VALUE) ? Long.MIN_VALUE : (l+1L);
      i ++;
      EQUAL(c.increment(), l);
    }

    EQUAL(l, Long.MIN_VALUE + 10L);
    EQUAL(c.currentValue(), Long.MIN_VALUE + 10L);
    EQUAL(i, 21L);
  }

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

    CountRotate c = CountRotate.synchronizedCountRotate(8L, 0L, 10L);
    long l = 8L;
    for (int i=0; i<20; i++) {
      EQUAL(c.currentValue(), l);
      l = (l == 10L) ? 0L : (l+1L);
      i++;
      EQUAL(c.increment(), l);
    }

    EQUAL(l, 7L);
  }

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

    CountRotate c = CountRotate.synchronizedCountRotate(
      new CountRotate(8L, 0L, 10L));
    long l = 8L;
    for (int i=0; i<20; i++) {
      EQUAL(c.currentValue(), l);
      l = (l == 10L) ? 0L : (l+1L);
      i++;
      EQUAL(c.increment(), l);
    }

    EQUAL(l, 7L);
  }
}
