/*
 * RecordTest 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.coverage.FunctionTester;
import ts.tester.function.print.*;
import java.util.*;
import ts.util.table.Record.SimpleEntry;

/**
 * {@link ts.util.table.Record Record}クラスの機能試験クラス。
 *
 * @author  佐藤隆之.
 * @version $Revision: 1.1.1.1 $, $Date: 2010-10-16 00:03:51 $
 */
public class RecordTest 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(RecordTest.class, (args.length == 0) ? null : args[0]);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  protected void preTesting()
  {
    MSG("Record クラスの機能試験を実行する。");
  }
  
  /* -- inner class -- */

  class HeaderEx<C> implements Header<C> {
    final static long serialVersionUID = 0L;
    private Set<C> keySet_ = new HashSet<C>();
    public int columnCount() {
      return keySet_.size();
    }
    public Enumeration<C> columns() {
      return Collections.enumeration(keySet_);
    }
    public boolean hasColumn(Object column) {
      return keySet_.contains(column);
    }
    public void addColumn(C column) {
      keySet_.add(column);
    }
  }

  class RecordEx<C,V> extends Record<C,V> {
    final static long serialVersionUID = 0L;
    private Map<C,V> valueMap_ = new HashMap<C,V>();
    private Header<C> header_ ;
    public RecordEx(Header<C> header) {
      header_ = header;
    }
    public Header<C> header() {
      return header_ ;
    }
    protected V getValue(Object column) {
      return valueMap_.get(column);
    }
    protected V putValue(C column, V value) {
      return valueMap_.put(column, value);
    }
    protected V removeValue(Object column) {
      return valueMap_.remove(column);
    }
  }

  /* -- test case -- */

  public void constructor_header()
  {
    MSG("コンストラクタ。");

    Header<String> header = new HeaderEx<String>();
    EQUAL(header.columnCount(), 0);

    Record<String,String> record = new RecordEx<String,String>(header);
    EQUAL(record.header(), header);
    EQUAL(record.size(), 0);
    TRUE(record.isEmpty());
  }

  public void size_and_isEmpty()
  {
    MSG("カラム数の取得と空の確認");

    Header<String> header = new HeaderEx<String>();
    EQUAL(header.columnCount(), 0);

    Record<String,String> record = new RecordEx<String,String>(header);
    EQUAL(record.header(), header);
    EQUAL(record.size(), 0);
    TRUE(record.isEmpty());

    header.addColumn("COL0");
    EQUAL(record.size(), 1);
    FALSE(record.isEmpty());

    header.addColumn("COL1");
    EQUAL(record.size(), 2);
    FALSE(record.isEmpty());

    header.addColumn("COL2");
    EQUAL(record.size(), 3);
    FALSE(record.isEmpty());
  }

  public void containsKey()
  {
    MSG("カラムを含んでいるかどうかの確認");

    Header<String> header = new HeaderEx<String>();
    EQUAL(header.columnCount(), 0);

    Record<String,String> record = new RecordEx<String,String>(header);
    EQUAL(record.header(), header);
    EQUAL(record.size(), 0);
    FALSE(header.hasColumn("C0"));
    FALSE(record.containsKey("C0"));
    FALSE(header.hasColumn("C1"));
    FALSE(record.containsKey("C1"));

    header.addColumn("C0");
    EQUAL(record.size(), 1);
    TRUE(header.hasColumn("C0"));
    TRUE(record.containsKey("C0"));
    FALSE(header.hasColumn("C1"));
    FALSE(record.containsKey("C1"));

    record.put("C1", "あいうえお");
    EQUAL(record.size(), 2);
    TRUE(header.hasColumn("C0"));
    TRUE(record.containsKey("C0"));
    TRUE(header.hasColumn("C1"));
    TRUE(record.containsKey("C1"));

    record.remove("C1");
    EQUAL(record.size(), 2);
    TRUE(header.hasColumn("C0"));
    TRUE(record.containsKey("C0"));
    TRUE(header.hasColumn("C1"));
    TRUE(record.containsKey("C1"));
  }

  public void containsValue()
  {
    MSG("値を含んでいるかどうかの確認");

    Header<String> header = new HeaderEx<String>();
    EQUAL(header.columnCount(), 0);

    Record<String,String> record = new RecordEx<String,String>(header);
    EQUAL(record.header(), header);
    EQUAL(record.size(), 0);

    FALSE(record.containsValue(null));
    FALSE(record.containsValue("あいうえお"));

    header.addColumn("C0");
    TRUE(record.containsValue(null));
    FALSE(record.containsValue("あいうえお"));

    record.put("C1", "あいうえお");
    TRUE(record.containsValue(null));
    TRUE(record.containsValue("あいうえお"));

    record.remove("C1");
    TRUE(record.containsValue(null));
    FALSE(record.containsValue("あいうえお"));
  }

  public void get_put_remove()
  {
    MSG("get, put, removeメソッドの確認");

    Header<String> header = new HeaderEx<String>();
    Record<String,String> record = new RecordEx<String,String>(header);

    EQUAL(record.header(), header);
    EQUAL(header.columnCount(), 0);
    EQUAL(record.size(), 0);
    FALSE(header.hasColumn("C0"));
    FALSE(header.hasColumn("C1"));
    NULL(record.get("C0"));
    NULL(record.get("C1"));

    header.addColumn("C0");
    EQUAL(header.columnCount(), 1);
    EQUAL(record.size(), 1);
    TRUE(header.hasColumn("C0"));
    FALSE(header.hasColumn("C1"));
    NULL(record.get("C0"));
    NULL(record.get("C1"));

    NULL(record.put("C1", "あいうえお"));
    EQUAL(header.columnCount(), 2);
    EQUAL(record.size(), 2);
    TRUE(header.hasColumn("C0"));
    TRUE(header.hasColumn("C1"));
    NULL(record.get("C0"));
    EQUAL(record.get("C1"), "あいうえお");

    EQUAL(record.put("C1", "XYZ"), "あいうえお");
    EQUAL(header.columnCount(), 2);
    EQUAL(record.size(), 2);
    TRUE(header.hasColumn("C0"));
    TRUE(header.hasColumn("C1"));
    NULL(record.get("C0"));
    EQUAL(record.get("C1"), "XYZ");

    EQUAL(record.remove("C1"), "XYZ");
    EQUAL(header.columnCount(), 2);
    EQUAL(record.size(), 2);
    TRUE(header.hasColumn("C0"));
    TRUE(header.hasColumn("C1"));
    NULL(record.get("C0"));
    NULL(record.get("C1"));

    EQUAL(record.remove("CX"), null);
    EQUAL(header.columnCount(), 2);
    EQUAL(record.size(), 2);
    TRUE(header.hasColumn("C0"));
    TRUE(header.hasColumn("C1"));
    NULL(record.get("C0"));
    NULL(record.get("C1"));

    record.put("C5", "aaa");
    EQUAL(header.columnCount(), 3);
    EQUAL(record.size(), 3);
    TRUE(header.hasColumn("C0"));
    TRUE(header.hasColumn("C1"));
    TRUE(header.hasColumn("C5"));
    NULL(record.get("C0"));
    NULL(record.get("C1"));
    EQUAL(record.get("C5"), "aaa");
  }

  public void putAll_clear()
  {
    MSG("putAllとclearを確認");

    Header<String> header = new HeaderEx<String>();
    Record<String,String> record = new RecordEx<String,String>(header);

    EQUAL(record.header(), header);
    EQUAL(header.columnCount(), 0);
    EQUAL(record.size(), 0);
    FALSE(header.hasColumn("C0"));
    FALSE(header.hasColumn("C1"));
    NULL(record.get("C0"));
    NULL(record.get("C1"));

    Map<String,String> m = new HashMap<String,String>();
    m.put("C0", "あいうえお");
    m.put("C1", "XYZ");

    record.putAll(m);
    EQUAL(header.columnCount(), 2);
    EQUAL(record.size(), 2);
    TRUE(header.hasColumn("C0"));
    TRUE(header.hasColumn("C1"));
    EQUAL(record.get("C0"), "あいうえお");
    EQUAL(record.get("C1"), "XYZ");

    record.clear();    
    EQUAL(header.columnCount(), 2);
    EQUAL(record.size(), 2);
    TRUE(header.hasColumn("C0"));
    TRUE(header.hasColumn("C1"));
    NULL(record.get("C0"));
    NULL(record.get("C1"));
  }

  public void keySet()
  {
    MSG("カラム・キーの集合を取得");

    Header<String> header = new HeaderEx<String>();
    Record<String,String> record = new RecordEx<String,String>(header);

    Set<String> set = record.keySet();
    EQUAL(set.size(), 0);

    header.addColumn("C0");
    record.put("C1", "xyz");

    set = record.keySet();
    EQUAL(set.size(), 2);
    TRUE(set.contains("C0"));
    TRUE(set.contains("C1"));

    Iterator<String> it = set.iterator();
    TRUE(it.hasNext());
    EQUAL(it.next(), "C0");
    it.remove();
    EQUAL(set.size(), 2);
    EQUAL(record.size(), 2);

    TRUE(it.hasNext());
    EQUAL(it.next(), "C1");
    FALSE(it.hasNext());
    it.remove();
    EQUAL(set.size(), 2);
    EQUAL(record.size(), 2);
  }

  public void values()
  {
    MSG("カラムの値の集合を取得");

    Header<String> header = new HeaderEx<String>();
    Record<String,String> record = new RecordEx<String,String>(header);

    header.addColumn("C0");
    record.put("C1", "xyz");

    Collection<String> c = record.values();
    EQUAL(c.size(), 2);
    TRUE(c.contains(null));
    TRUE(c.contains("xyz"));

    Iterator<String> it = c.iterator(); 
    TRUE(it.hasNext());
    EQUAL(it.next(), null);
    it.remove();
    EQUAL(record.size(), 2);
    EQUAL(c.size(), 2);

    TRUE(it.hasNext());
    EQUAL(it.next(), "xyz");
    it.remove();
    EQUAL(record.size(), 2);
    EQUAL(c.size(), 2);

    FALSE(it.hasNext());
  }

  public void entrySet()
  {
    MSG("カラム・キーと値の組の集合を取得");

    Header<String> header = new HeaderEx<String>();
    Record<String,String> record = new RecordEx<String,String>(header);

    Set<Map.Entry<String,String>> set = record.entrySet();
    EQUAL(set.size(), 0);
    Iterator<Map.Entry<String,String>> it = set.iterator();
    FALSE(it.hasNext());

    header.addColumn("C0");
    record.put("C1", "xyz");

    set = record.entrySet();
    EQUAL(set.size(), 2);

    it = set.iterator();
    TRUE(it.hasNext());
    Map.Entry<String,String> entry = it.next();
    EQUAL(entry.getKey(), "C0");
    EQUAL(entry.getValue(), null);
    it.remove();
    EQUAL(record.size(), 2);
    EQUAL(set.size(), 2);

    TRUE(it.hasNext());
    entry = it.next();
    EQUAL(entry.getKey(), "C1");
    EQUAL(entry.getValue(), "xyz");
    FALSE(it.hasNext());
    it.remove();
    EQUAL(record.size(), 2);
    EQUAL(set.size(), 2);
  }

  public void _equals()
  {
    MSG("他のレコードと内容を比較");

    Header<String> header = new HeaderEx<String>();
    Record<String,String> record = new RecordEx<String,String>(header);
    Record<String,String> r2 = new RecordEx<String,String>(header);

    FALSE(record.equals(null));
    TRUE(record.equals(record));
    TRUE(record.equals(r2));
    TRUE(r2.equals(record));

    header.addColumn("C0");
    TRUE(record.equals(record));
    FALSE(record.equals(null));
    TRUE(record.equals(r2));
    TRUE(r2.equals(record));

    record.put("C1", "xyz");
    TRUE(record.equals(record));
    FALSE(record.equals(null));
    FALSE(record.equals(r2));
    FALSE(r2.equals(record));

    Map<String,String> m = new HashMap<String,String>();
    FALSE(record.equals(m));

    m.put("C0", null);
    m.put("C1", "xyz");
    FALSE(record.equals(null));
    FALSE(record.equals(r2));
    FALSE(r2.equals(record));
    TRUE(record.equals(m));
    TRUE(m.equals(record));
    FALSE(r2.equals(m));
    FALSE(m.equals(r2));

    FALSE(record.equals(new Integer(123)));

    Map<String,Integer> m2 = new HashMap<String,Integer>();
    m2.put("C0", new Integer(123));
    m2.put("C1", new Integer(123));
    FALSE(record.equals(m2));
  }

  public void _hashCode()
  {
    MSG("ハッシュ・コードを取得");

    Header<String> header = new HeaderEx<String>();
    Record<String,String> record = new RecordEx<String,String>(header);
    Record<String,String> r2 = new RecordEx<String,String>(header);

    EQUAL(record.hashCode(), r2.hashCode());

    header.addColumn("C0");

    EQUAL(record.hashCode(), r2.hashCode());

    record.put("C1", "xyz");
    r2.put("C1", "xyz");

    EQUAL(record.hashCode(), r2.hashCode());
  }

  public void _toString()
  {
    MSG("内容を表す文字列を取得");

    Header<String> header = new HeaderEx<String>();
    Record<String,String> record = new RecordEx<String,String>(header);

    EQUAL(record.toString(), "{}");

    header.addColumn("C0");
    EQUAL(record.toString(), "{C0=null}");

    record.put("C1", "V1");
    record.put("C2", "V2");
    String s = record.toString();
    EQUAL(s,s);
    TRUE(s.indexOf("C0=null") >= 0);
    TRUE(s.indexOf("C1=V1") >= 0);
    TRUE(s.indexOf("C2=V2") >= 0);

    record.remove("C1");
    s = record.toString();
    EQUAL(s,s);
    TRUE(s.indexOf("C0=null") >= 0);
    TRUE(s.indexOf("C1=null") >= 0);
    TRUE(s.indexOf("C2=V2") >= 0);
  }

  public void satisfyCondition_map_map()
  {
    MSG("レコードが条件を満たしているかどうかを確認");

    Header<String> header = new HeaderEx<String>();
    Record<String,Object> r0 = new RecordEx<String,Object>(header);
    Map<String,Object> c0 = new HashMap<String,Object>();

    TRUE(r0.satisfyCondition(c0));

    c0.put("a", "b");
    FALSE(r0.satisfyCondition(c0));

    c0.clear();
    r0.put("A", "B");
    TRUE(r0.satisfyCondition(c0));

    c0.put("A", "B");
    TRUE(r0.satisfyCondition(c0));

    c0.put("A", "C");
    FALSE(r0.satisfyCondition(c0));

    r0.put("A", "C");
    TRUE(r0.satisfyCondition(c0));

    c0.put("B", null);
    FALSE(r0.satisfyCondition(c0));

    r0.put("B", "x");
    FALSE(r0.satisfyCondition(c0));

    r0.put("B", null);
    TRUE(r0.satisfyCondition(c0));
  }

  public void SimpleEntry_constructor_key_value()
  {
    SimpleEntry<String,String> entry;
    
    entry = new SimpleEntry<String,String>("C1", "V1");
    EQUAL(entry.getKey(), "C1");
    EQUAL(entry.getValue(), "V1");

    entry = new SimpleEntry<String,String>(null, "V1");
    EQUAL(entry.getKey(), null);
    EQUAL(entry.getValue(), "V1");

    entry = new SimpleEntry<String,String>("C1", null);
    EQUAL(entry.getKey(), "C1");
    EQUAL(entry.getValue(), null);
  }

  public void SimpleEntry_constructor_entry()
  {
    SimpleEntry<String,String> entry;
    entry = new SimpleEntry<String,String>("C1", "V1");
    EQUAL(entry.getKey(), "C1");
    EQUAL(entry.getValue(), "V1");

    SimpleEntry<String,String> entry2 = new SimpleEntry<String,String>(entry);
    EQUAL(entry2.getKey(), "C1");
    EQUAL(entry2.getValue(), "V1");
  }

  public void SimpleEntry_setValue()
  {
    SimpleEntry<String,String> entry;
    entry = new SimpleEntry<String,String>("C1", "V1");
    EQUAL(entry.getKey(), "C1");
    EQUAL(entry.getValue(), "V1");

    entry.setValue("V2");
    EQUAL(entry.getKey(), "C1");
    EQUAL(entry.getValue(), "V2");

    entry.setValue(null);
    EQUAL(entry.getKey(), "C1");
    EQUAL(entry.getValue(), null);
  }

  public void SimpleEntry_equals()
  {
    SimpleEntry<String,String> entry0, entry1;
    entry0 = new SimpleEntry<String,String>("C1", "V1");
    entry1 = new SimpleEntry<String,String>("C1", "V1");
    TRUE(entry0.equals(entry1));

    entry0 = new SimpleEntry<String,String>("C1", "V1");
    entry1 = new SimpleEntry<String,String>("C1", "V2");
    FALSE(entry0.equals(entry1));

    entry0 = new SimpleEntry<String,String>("C1", "V1");
    entry1 = new SimpleEntry<String,String>(null, null);
    FALSE(entry0.equals(entry1));

    entry0 = new SimpleEntry<String,String>(null, null);
    entry1 = new SimpleEntry<String,String>("C1", "V2");
    FALSE(entry0.equals(entry1));

    entry0 = new SimpleEntry<String,String>(null, null);
    entry1 = new SimpleEntry<String,String>(null, null);
    TRUE(entry0.equals(entry1));

    FALSE(entry0.equals(new Object()));
  }

  public void SimpleEntry_hashCode()
  {
    SimpleEntry<String,String> entry0, entry1;
    entry0 = new SimpleEntry<String,String>("C1", "V1");
    entry1 = new SimpleEntry<String,String>("C1", "V1");
    TRUE(entry0.equals(entry1));
    EQUAL(entry0.hashCode(), entry1.hashCode());

    entry0 = new SimpleEntry<String,String>(null, null);
    entry1 = new SimpleEntry<String,String>(null, null);
    TRUE(entry0.equals(entry1));
    EQUAL(entry0.hashCode(), entry1.hashCode());
  }

  public void SimpleEntry_toString()
  {
    SimpleEntry<String,String> entry;

    entry = new SimpleEntry<String,String>("C1", "V1");
    EQUAL(entry.toString(), "C1=V1");

    entry = new SimpleEntry<String,String>(null, null);
    EQUAL(entry.toString(), "null=null");
  }
}

