/*
 * ConstraintTrigger_normalTest 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.table;

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

/**
 * {@link ts.util.table.ConstraintTrigger ConstraintTrigger}クラスの機能試験クラス。
 *
 * @author  佐藤隆之.
 * @version $Revision: 1.2 $, $Date: 2011-09-04 15:10:34 $
 */
public class ConstraintTrigger_normalTest extends FunctionTester
{
  public static void main(String[] args)
  {
    try {
      PrinterGroup group = new PrinterGroup();
      group.addPrinter(new ConsolePrinter());
      setPrinter(group);

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


  boolean error0, error1, error2 ;
  StringBuffer logBuf;

  protected void preInvocation(String method)
  {
    logBuf = new StringBuffer();
    error0 = error1 = error2 = false;
  }

  enum Reason { Error0, Error1, Error2 }

  @SuppressWarnings("serial")
  Constraint<String,String> constraint0 = new Constraint<String,String>() {
    public void check(Trigger.Action a, Table<String,String> t,
    Map<String,String> r) throws ConstraintViolationException {
      logBuf.append("[CONSTRAINT0]");
      if (error0) throw new ConstraintViolationException(a, Reason.Error0);
    }
  };
  @SuppressWarnings("serial")
  Constraint<String,String> constraint1 = new Constraint<String,String>() {
    public void check(Trigger.Action a, Table<String,String> t,
    Map<String,String> r) throws ConstraintViolationException {
      logBuf.append("[CONSTRAINT1]");
      if (error1) throw new ConstraintViolationException(a, Reason.Error1);
    }
  };
  @SuppressWarnings("serial")
  Constraint<String,String> constraint2 = new Constraint<String,String>() {
    public void check(Trigger.Action a, Table<String,String> t,
    Map<String,String> r) throws ConstraintViolationException {
      logBuf.append("[CONSTRAINT2]");
      if (error2) throw new ConstraintViolationException(a, Reason.Error2);
    }
  };
  

  /* -- test case -- */

  public void constructor()
  {
    MSG("引数をもたないコンストラクタの動作確認。");

    ConstraintTrigger<String,String> trigger = 
      new ConstraintTrigger<String,String>();

    ObjectInspector oi = new ObjectInspector(this);
    oi.expect("isImmediate_", true);
    oi.expect("constraintsForAppend_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("constraintsForUpdate_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("constraintsForDelete_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("serialVersionUID", ConstraintTrigger.serialVersionUID);

    oi.inspect(trigger);
  }

  public void constructor_boolean()
  {
    MSG("コンストラクタの動作確認。");

    ConstraintTrigger<String,String> trigger = 
      new ConstraintTrigger<String,String>(true);

    ObjectInspector oi = new ObjectInspector(this);
    oi.expect("isImmediate_", true);
    oi.expect("constraintsForAppend_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("constraintsForUpdate_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("constraintsForDelete_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("serialVersionUID", ConstraintTrigger.serialVersionUID);
    oi.inspect(trigger);

    ConstraintTrigger<String,String> trigger2 = 
      new ConstraintTrigger<String,String>(false);

    oi.expect("isImmediate_", false);
    oi.expect("constraintsForAppend_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("constraintsForUpdate_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("constraintsForDelete_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("serialVersionUID", ConstraintTrigger.serialVersionUID);
    oi.inspect(trigger2);
  }

  public void addConstraintForAppend_Constraint()
  {
    MSG("addConstraintForAppendメソッドの動作確認。");

    ConstraintTrigger<String,String> trigger = 
      new ConstraintTrigger<String,String>(true);

    ObjectInspector oi = new ObjectInspector(this);
    oi.expect("isImmediate_", true);
    oi.expect("constraintsForAppend_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("constraintsForUpdate_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("constraintsForDelete_",
      new LinkedList<Constraint<String,String>>());
    oi.expect("serialVersionUID", ConstraintTrigger.serialVersionUID);
    oi.inspect(trigger);

    trigger.addConstraintForAppend(constraint0);

    List<Constraint> lst = new ArrayList<Constraint>();
    lst.add(constraint0);
    oi.expect("constraintsForAppend_", lst);
    oi.inspect(trigger);

    trigger.addConstraintForAppend(constraint1);
    lst.add(constraint1);
    oi.inspect(trigger);
  }

  public void addConstraintForUpdate_Constraint()
  {
    MSG("addConstraintForUpdateメソッドの動作確認。");

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>(false);
    
    ObjectInspector oi = new ObjectInspector(this);
    oi.expect("isImmediate_", false);
    oi.expect("constraintsForAppend_", Collections.emptyList());
    oi.expect("constraintsForUpdate_", Collections.emptyList());
    oi.expect("constraintsForDelete_", Collections.emptyList());
    oi.expect("serialVersionUID", ConstraintTrigger.serialVersionUID);
    oi.inspect(trigger);

    trigger.addConstraintForUpdate(constraint0);

    List<Constraint> lst = new ArrayList<Constraint>();
    lst.add(constraint0);
    oi.expect("constraintsForUpdate_", lst);
    oi.inspect(trigger);

    trigger.addConstraintForUpdate(constraint1);
    lst.add(constraint1);
    oi.inspect(trigger);
  }

  public void addConstraintForDelete_Constraint()
  {
    MSG("addConstraintForDeleteメソッドの動作確認。");

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>(false);

    ObjectInspector oi = new ObjectInspector(this);
    oi.expect("isImmediate_", false);
    oi.expect("constraintsForAppend_", Collections.emptyList());
    oi.expect("constraintsForUpdate_", Collections.emptyList());
    oi.expect("constraintsForDelete_", Collections.emptyList());
    oi.expect("serialVersionUID", ConstraintTrigger.serialVersionUID);
    oi.inspect(trigger);

    List<Constraint> lst = new ArrayList<Constraint>();
    lst.add(constraint0);
    oi.expect("constraintsForAppend_", lst);

    trigger.addConstraintForAppend(constraint0);

    oi.inspect(trigger);
  }

  public void preAppend_Table_Map()
  {
    MSG("preAppendメソッドの動作確認。");

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>();

    trigger.addConstraintForAppend(constraint0);
    trigger.addConstraintForAppend(constraint1);
    trigger.addConstraintForAppend(constraint2);

    trigger.preAppend(tab, rec);

    EQUAL(logBuf.toString(), "[CONSTRAINT0][CONSTRAINT1][CONSTRAINT2]");
  }

  public void preAppend_Table_Map_1()
  {
    MSG("preAppendメソッドの動作確認（制約違反即時スロー）。");

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>();

    trigger.addConstraintForAppend(constraint0);
    trigger.addConstraintForAppend(constraint1);
    trigger.addConstraintForAppend(constraint2);

    error1 = true;
    error2 = true;
    try {
      trigger.preAppend(tab, rec);
    }
    catch (ConstraintViolationException e) {
      EQUAL(e.getAction(), Trigger.Action.Append);
      EQUAL(e.getReason(), Reason.Error1);
      NULL(e.next());
    }
    EQUAL(logBuf.toString(), "[CONSTRAINT0][CONSTRAINT1]");
  }

  public void preAppend_Table_Map_2()
  {
    MSG("preAppendメソッドの動作確認（制約違反全判定後スロー）。");

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>(false);

    trigger.addConstraintForAppend(constraint0);
    trigger.addConstraintForAppend(constraint1);
    trigger.addConstraintForAppend(constraint2);

    error1 = true;
    error2 = true;
    try {
      trigger.preAppend(tab, rec);
    }
    catch (ConstraintViolationException e) {
      EQUAL(e.getAction(), Trigger.Action.Append);
      EQUAL(e.getReason(), Reason.Error1);
      EQUAL(e.next().getAction(), Trigger.Action.Append);
      EQUAL(e.next().getReason(), Reason.Error2);
      NULL(e.next().next());
    }
    EQUAL(logBuf.toString(), "[CONSTRAINT0][CONSTRAINT1][CONSTRAINT2]");
  }

  public void preUpdate_Table_Map_Map()
  {
    MSG("preUpdateメソッドの動作確認。");

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>();

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();
    Map<String,String> dst = new HashMap<String,String>();

    trigger.addConstraintForUpdate(constraint0);
    trigger.addConstraintForUpdate(constraint1);
    trigger.addConstraintForUpdate(constraint2);

    trigger.preUpdate(tab, rec, dst);

    EQUAL(logBuf.toString(), "[CONSTRAINT0][CONSTRAINT1][CONSTRAINT2]");
  }

  public void preUpdate_Table_Map_Map_1()
  {
    MSG("preUpdateメソッドの動作確認（制約違反即時スロー）。");

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();
    Map<String,String> dst = new HashMap<String,String>();

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>();

    trigger.addConstraintForUpdate(constraint0);
    trigger.addConstraintForUpdate(constraint1);
    trigger.addConstraintForUpdate(constraint2);

    error1 = true;
    error2 = true;
    try {
      trigger.preUpdate(tab, rec, dst);
    }
    catch (ConstraintViolationException e) {
      EQUAL(e.getAction(), Trigger.Action.Update);
      EQUAL(e.getReason(), Reason.Error1);
      NULL(e.next());
    }
    EQUAL(logBuf.toString(), "[CONSTRAINT0][CONSTRAINT1]");
  }

  public void preUpdate_Table_Map_Map_2()
  {
    MSG("preUpdateメソッドの動作確認（制約違反全判定後スロー）。");

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();
    Map<String,String> dst = new HashMap<String,String>();

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>(false);

    trigger.addConstraintForUpdate(constraint0);
    trigger.addConstraintForUpdate(constraint1);
    trigger.addConstraintForUpdate(constraint2);

    error1 = true;
    error2 = true;
    try {
      trigger.preUpdate(tab, rec, dst);
    }
    catch (ConstraintViolationException e) {
      EQUAL(e.getAction(), Trigger.Action.Update);
      EQUAL(e.getReason(), Reason.Error1);
      EQUAL(e.next().getAction(), Trigger.Action.Update);
      EQUAL(e.next().getReason(), Reason.Error2);
      NULL(e.next().next());
    }
    EQUAL(logBuf.toString(), "[CONSTRAINT0][CONSTRAINT1][CONSTRAINT2]");
  }

  public void preDelete_Table_Map()
  {
    MSG("preDeleteメソッドの動作確認。");

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>();

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();

    trigger.addConstraintForDelete(constraint0);
    trigger.addConstraintForDelete(constraint1);
    trigger.addConstraintForDelete(constraint2);

    trigger.preDelete(tab, rec);

    EQUAL(logBuf.toString(), "[CONSTRAINT0][CONSTRAINT1][CONSTRAINT2]");
  }

  public void preDelete_Table_Map_1()
  {
    MSG("preDeleteメソッドの動作確認（制約違反即時スロー）。");

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>();

    trigger.addConstraintForDelete(constraint0);
    trigger.addConstraintForDelete(constraint1);
    trigger.addConstraintForDelete(constraint2);

    error1 = true;
    error2 = true;
    try {
      trigger.preDelete(tab, rec);
    }
    catch (ConstraintViolationException e) {
      EQUAL(e.getAction(), Trigger.Action.Delete);
      EQUAL(e.getReason(), Reason.Error1);
      NULL(e.next());
    }
    EQUAL(logBuf.toString(), "[CONSTRAINT0][CONSTRAINT1]");
  }

  public void preDelete_Table_Map_2()
  {
    MSG("preDeleteメソッドの動作確認（制約違反全判定後スロー）。");

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>(false);

    trigger.addConstraintForDelete(constraint0);
    trigger.addConstraintForDelete(constraint1);
    trigger.addConstraintForDelete(constraint2);

    error1 = true;
    error2 = true;
    try {
      trigger.preDelete(tab, rec);
    }
    catch (ConstraintViolationException e) {
      EQUAL(e.getAction(), Trigger.Action.Delete);
      EQUAL(e.getReason(), Reason.Error1);
      EQUAL(e.next().getAction(), Trigger.Action.Delete);
      EQUAL(e.next().getReason(), Reason.Error2);
      NULL(e.next().next());
    }
    EQUAL(logBuf.toString(), "[CONSTRAINT0][CONSTRAINT1][CONSTRAINT2]");
  }

  public void postAppend_Table_Map()
  {
    MSG("postAppendメソッドの動作確認。");

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>();

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();

    trigger.postAppend(tab, rec);
    EQUAL(logBuf.toString(), "");

    trigger.addConstraintForAppend(constraint0);
    trigger.addConstraintForUpdate(constraint0);
    trigger.addConstraintForDelete(constraint0);

    trigger.postAppend(tab, rec);
    EQUAL(logBuf.toString(), "");
  }

  public void postUpdate_Table_Map_Map()
  {
    MSG("postUpdateメソッドの動作確認。");

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>();

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();
    Map<String,String> dest = new HashMap<String,String>();

    trigger.postUpdate(tab, rec, dest);
    EQUAL(logBuf.toString(), "");

    trigger.addConstraintForAppend(constraint0);
    trigger.addConstraintForUpdate(constraint1);
    trigger.addConstraintForDelete(constraint2);

    trigger.postUpdate(tab, rec, dest);
    EQUAL(logBuf.toString(), "");
  }

  public void postDelete_Table_Map()
  {
    MSG("postDeleteメソッドの動作確認。");

    ConstraintTrigger<String,String> trigger =
      new ConstraintTrigger<String,String>();

    Table<String,String> tab = new ArrayListTable<String,String>();
    Map<String,String> rec = tab.appendNew();

    trigger.postDelete(tab, rec);
    EQUAL(logBuf.toString(), "");

    trigger.addConstraintForAppend(constraint0);
    trigger.addConstraintForUpdate(constraint1);
    trigger.addConstraintForDelete(constraint2);

    trigger.postDelete(tab, rec);
    EQUAL(logBuf.toString(), "");
  }
}
