/*
 * DefaultResourceTest 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.resource;

import ts.tester.function.coverage.FunctionTester;
import ts.tester.function.print.*;
import ts.util.resource.hierarchy.*;
import java.io.*;
import java.util.*;

/**
 * <code>DefaultResource</code>クラスの機能試験クラス。
 *
 * @author  佐藤隆之. 
 * @version $Revision: 1.2 $, $Date: 2010-11-14 11:51:01 $
 */
public class DefaultResourceTest 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(DefaultResourceTest.class, (args.length == 0) ? null : args[0]);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  class DefaultResourceEx extends DefaultResource {
    public DefaultResourceEx() {}
    public DefaultResourceEx(DefaultResource res) { super(res); }
    public void load(InputStream stream) throws IOException {}
    public void save(OutputStream stream) throws IOException {}
    public String getPath() { return ""; }
    public DefaultResource createResource() {
      return new DefaultResourceEx(this);
    }
  }

  /* -- test case -- */

  public void default_constructor()
  {
    DefaultResource res = new DefaultResourceEx();
    NOTNULL(res);
    NOTNULL(res.getBaseElement());
  }

  public void copy_constructor()
  {
    DefaultResource res = new DefaultResourceEx();
    DefaultResource res2 = new DefaultResourceEx(res);
    EQUAL(res.getBaseElement(), res2.getBaseElement());
  }

  public void copy_constructor_1()
  {
    DefaultResource res = new DefaultResourceEx();
    try {
      DefaultResource res2 = new DefaultResourceEx(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
  }

  protected void load(DefaultResource res)
  {
    Element e0 = new Element("sample");
    res.getBaseElement().addChild(e0);

    Element e1 = new Element("title");
    e1.setValue("タイトル");
    e0.addChild(e1);

    Element e2 = new Element("body");
    e2.putAttribute("type", "typeA");
    e2.setValue("本文。");
    e0.addChild(e2);

    Element e3 = new Element("a");
    e3.putAttribute("id", "a1");
    e3.putAttribute("name", "A1");
    e3.setValue("あ");
    e2.addChild(e3);

    Element e4 = new Element("b");
    e4.putAttribute("id", "b1");
    e4.putAttribute("name", "B1");
    e4.setValue("び");
    e2.addChild(e4);

    Element e5 = new Element("b");
    e5.putAttribute("id", "b2");
    e5.putAttribute("name", "B2");
    e5.setValue("びび");
    e2.addChild(e5);

    Element e6 = new Element("b");
    e6.putAttribute("id", "b3");
    e2.addChild(e6);

    Element e7 = new Element("c");
    e7.putAttribute("id", "c1");
    e7.putAttribute("name", "C1");
    e7.setValue("し");
    e2.addChild(e7);

    Element e8 = new Element("c");
    e8.putAttribute("id", "c2");
    e8.putAttribute("name", "C2");
    e8.setValue("しし");
    e2.addChild(e8);

    Element e9 = new Element("c");
    e9.putAttribute("id", "c3");
    e9.setValue("\n   あい  う え    お\n          ");
    e2.addChild(e9);
  }

  public void findFirstElement()
  {
    MSG("リソースデータが空の場合");

    DefaultResource res = new DefaultResourceEx();

    EQUAL(res.findFirstElement(""), res.getBaseElement());
    EQUAL(res.findFirstElement("sample"), null);
    EQUAL(res.findFirstElement("sample.title"), null);
  }

  public void findFirstElement_1()
  {
    MSG("通常の操作");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.findFirstElement(""), res.getBaseElement());
    EQUAL(res.findFirstElement("").getName(), "");
    EQUAL(res.findFirstElement("sample").getName(), "sample");
    EQUAL(res.findFirstElement("sample.title").getName(), "title");
  }

  public void findFirstElement_2()
  {
    MSG("存在しないキーの場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    NULL(res.findFirstElement("example"));
    NULL(res.findFirstElement("sample.header"));
  }

  public void findFirstElement_3()
  {
    MSG("キーが空文字列の場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.findFirstElement(""), res.getBaseElement());
    EQUAL(res.findFirstElement("").getName(), "");
  }

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

    DefaultResource res = new DefaultResourceEx();
    load(res);

    try {
      res.findFirstElement(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
  }

  public void findFirstElement_5()
  {
    MSG("属性を持つキーの場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.findFirstElement("sample.body(type=typeA)").getName(), "body");
    EQUAL(res.findFirstElement("sample.body.a(id=a1)").getName(), "a");
    EQUAL(res.findFirstElement("sample.body.b(id=b1)").getName(), "b");
    EQUAL(res.findFirstElement("sample.body.c(id=c1)").getName(), "c");
  }

  public void findFirstElement_6()
  {
    MSG("一つの要素に属性が複数ある場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.findFirstElement("sample.body.a(id=a1,name=A1)").getName(), "a");
    EQUAL(res.findFirstElement("sample.body.b(name=B2,id=b2)").getName(), "b");
    EQUAL(res.findFirstElement("sample.body.c(id=c1,name=C1)").getName(), "c");

    NULL(res.findFirstElement("sample.body.a(id=a1,name=A2)"));
    NULL(res.findFirstElement("sample.body.b(name=B1,id=b2)"));
    NULL(res.findFirstElement("sample.body.c(id=c1,name=C2)"));
  }

  public void findFirstElement_7()
  {
    MSG("属性のない要素に対して属性をもつキーを指定した場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    NULL(res.findFirstElement("sample.title(id=TTT)"));
  }

  public void findFirstElement_8()
  {
    MSG("不正なキーを指定した場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    try {
      res.findFirstElement("sample.");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.findFirstElement("sample.body(");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void findFirstElement_9()
  {
    MSG("キーの中に*が存在する場合");
    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.findFirstElement("*").getName(), "sample");
    EQUAL(res.findFirstElement("sample.*").getName(), "title");
    EQUAL(res.findFirstElement("sample.body.*").getName(), "a");
    EQUAL(res.findFirstElement("sample.body.*(id=a1)").getName(), "a");
    EQUAL(res.findFirstElement("sample.body.*(id=b1)").getName(), "b");
    EQUAL(res.findFirstElement("sample.body.*(id=b2)").getName(), "b");
    EQUAL(res.findFirstElement("sample.body.*(id=c1)").getName(), "c");
    EQUAL(res.findFirstElement("sample.body.*(id=c2)").getName(), "c");
  }

  public void getFirstValue()
  {
    MSG("通常の操作");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.getFirstValue(""), "");
    EQUAL(res.getFirstValue("sample.title"), "タイトル");
    EQUAL(res.getFirstValue("sample.body"), "本文。");
    EQUAL(res.getFirstValue("sample.body.a"), "あ");
    EQUAL(res.getFirstValue("sample.body.b"), "び");
    EQUAL(res.getFirstValue("sample.body.c"), "し");
  }

  public void getFirstValue_1()
  {
    MSG("キーが属性を持つ場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.getFirstValue("sample.body(type=typeA)"), "本文。");
    EQUAL(res.getFirstValue("sample.body.a(id=a1)"), "あ");
    EQUAL(res.getFirstValue("sample.body.a(name=A1)"), "あ");
    EQUAL(res.getFirstValue("sample.body.b(id=b1)"), "び");
    EQUAL(res.getFirstValue("sample.body.b(id=b2)"), "びび");
    EQUAL(res.getFirstValue("sample.body.b(id=b3)"), "");
    EQUAL(res.getFirstValue("sample.body.c(id=c1)"), "し");
    EQUAL(res.getFirstValue("sample.body.c(id=c2)"), "しし");
    EQUAL(res.getFirstValue("sample.body.c(id=c3)"),
      "\n   あい  う え    お\n          ");
  }

  public void getFirstValue_2()
  {
    MSG("キーに*が含まれている場合");
    DefaultResource res = new DefaultResourceEx();
    load(res);
    EQUAL(res.getFirstValue("sample.*(type=typeA)"), "本文。");
    EQUAL(res.getFirstValue("*.*(type=typeA)"), "本文。");
    EQUAL(res.getFirstValue("*.body(type=typeA)"), "本文。");
    EQUAL(res.getFirstValue("*.*.*(id=a1)"), "あ");
    EQUAL(res.getFirstValue("*.body.a(id=a1)"), "あ");
    EQUAL(res.getFirstValue("sample.*.a(id=a1)"), "あ");
    EQUAL(res.getFirstValue("sample.body.*(id=a1)"), "あ");
  }

  public void findAllElements()
  {
    MSG("通常の場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<Element> elemLst = res.findAllElements("");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "");
    EQUAL(elemLst.get(0), res.getBaseElement());

    elemLst = res.findAllElements("sample");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "sample");

    elemLst = res.findAllElements("sample.title");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "title");

    elemLst = res.findAllElements("sample.body.a");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "a");

    elemLst = res.findAllElements("sample.body.b");
    EQUAL(elemLst.size(), 3);
    EQUAL(elemLst.get(0).getName(), "b");
    EQUAL(elemLst.get(1).getName(), "b");
    EQUAL(elemLst.get(2).getName(), "b");

    elemLst = res.findAllElements("sample.body.c");
    EQUAL(elemLst.size(), 3);
    EQUAL(elemLst.get(0).getName(), "c");
    EQUAL(elemLst.get(1).getName(), "c");
    EQUAL(elemLst.get(2).getName(), "c");
  }

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

    DefaultResource res = new DefaultResourceEx();
    load(res);

    try {
      res.findAllElements(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
  }

  public void findAllElements_2()
  {
    MSG("引数が空文字列の場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<Element> elemLst = res.findAllElements("");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0), res.getBaseElement());
  }

  public void findAllElemnets_3()
  {
    MSG("存在しないキーの場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<Element> elemLst = res.findAllElements("abc");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.bb");
    EQUAL(elemLst.size(), 0);
  }

  public void findAllElement_4()
  {
    MSG("属性を持つキーの場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<Element> elemLst = res.findAllElements("sample.body(type=typeA)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "body");

    elemLst = res.findAllElements("sample.body(type=typeB)");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.a(id=a1)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "a");

    elemLst = res.findAllElements("sample.body.a(id=a2)");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.b(id=b1)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "b");

    elemLst = res.findAllElements("sample.body.b(id=b2)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "b");

    elemLst = res.findAllElements("sample.body.b(id=b3)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "b");

    elemLst = res.findAllElements("sample.body.b(id=b4)");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.c(id=c1)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "c");

    elemLst = res.findAllElements("sample.body.c(id=c2)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "c");

    elemLst = res.findAllElements("sample.body.c(id=c3)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "c");

    elemLst = res.findAllElements("sample.body.c(id=c4)");
    EQUAL(elemLst.size(), 0);
  }

  public void findAllElements_5()
  {
    MSG("一つの要素の属性が複数ある場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<Element> elemLst;

    elemLst = res.findAllElements("sample.body.a(id=a1,name=A1)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "a");

    elemLst = res.findAllElements("sample.body.a(id=a1, name=A1)");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.a(id=a1, name =A1)");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.a(id=a1,name= A1)");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.a(id=a1,name=A1 )");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.a(id=a1,name=A2)");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.a(id=a2,name=A1)");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.b(id=b1,name=B1)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "b");

    elemLst = res.findAllElements("sample.body.b(id=b1,name=B2)");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.b(id=b2,name=B1)");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.c(id=c1,name=C1)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "c");

    elemLst = res.findAllElements("sample.body.c(id=c1,name=C2)");
    EQUAL(elemLst.size(), 0);

    elemLst = res.findAllElements("sample.body.c(id=c2,name=C1)");
    EQUAL(elemLst.size(), 0);
  }

  public void findAllElements_6()
  {
    MSG("不正なキーの場合");

    DefaultResource res = new DefaultResourceEx();
    try {
      res.findAllElements("sample.body.a(id=a1");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    }
  }
  
  public void findAllElements_7()
  {
    MSG("空のリソースの場合");

    DefaultResource res = new DefaultResourceEx();
    List<Element> elemLst = res.findAllElements("sample.title");
    EQUAL(elemLst.size(), 0);
  }

  public void findAllElements_8()
  {
    MSG("キーに*が含まれている場合");
    DefaultResource res = new DefaultResourceEx();
    load(res);
    List<Element> elemLst;
    elemLst = res.findAllElements("*");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "sample");
    elemLst = res.findAllElements("sample.*");
    EQUAL(elemLst.size(), 2);
    EQUAL(elemLst.get(0).getName(), "title");
    EQUAL(elemLst.get(1).getName(), "body");
    elemLst = res.findAllElements("sample.body.*");
    EQUAL(elemLst.size(), 7);
    EQUAL(elemLst.get(0).getName(), "a");
    EQUAL(elemLst.get(1).getName(), "b");
    EQUAL(elemLst.get(2).getName(), "b");
    EQUAL(elemLst.get(3).getName(), "b");
    EQUAL(elemLst.get(4).getName(), "c");
    EQUAL(elemLst.get(5).getName(), "c");
    EQUAL(elemLst.get(6).getName(), "c");
    elemLst = res.findAllElements("sample.body.*(id=a1)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "a");
    EQUAL(elemLst.get(0).getAttributes().get("id"), "a1");
    elemLst = res.findAllElements("sample.body.*(id=b1)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "b");
    EQUAL(elemLst.get(0).getAttributes().get("id"), "b1");
    elemLst = res.findAllElements("sample.body.*(id=c2)");
    EQUAL(elemLst.size(), 1);
    EQUAL(elemLst.get(0).getName(), "c");
    EQUAL(elemLst.get(0).getAttributes().get("id"), "c2");
  }

  public void getValues()
  {
    MSG("通常の場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<String> lst = res.getValues("sample.title");
    EQUAL(lst.size(), 1);
    EQUAL(lst.get(0), "タイトル");

    lst = res.getValues("sample.body");
    EQUAL(lst.size(), 1);
    EQUAL(lst.get(0), "本文。");

    lst = res.getValues("sample.body.a");
    EQUAL(lst.size(), 1);
    EQUAL(lst.get(0), "あ");

    lst = res.getValues("sample.body.b");
    EQUAL(lst.size(), 3);
    EQUAL(lst.get(0), "び");
    EQUAL(lst.get(1), "びび");
    EQUAL(lst.get(2), "");

    lst = res.getValues("sample.body.b(name=B2)");
    EQUAL(lst.size(), 1);
    EQUAL(lst.get(0), "びび");

    lst = res.getValues("sample.body.c(id=c3)");
    EQUAL(lst.size(), 1);
    EQUAL(lst.get(0), "\n   あい  う え    お\n          ");
  }

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

    DefaultResource res = new DefaultResourceEx();
    load(res);

    try {
      res.getValues(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void getValues_2()
  {
    MSG("引数が空文字列の場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<String> lst = res.getValues("");
    EQUAL(lst.size(), 1);
    EQUAL(lst.get(0), "");
  }

  public void getValues_3()
  {
    MSG("存在しないキーを指定した場合");
    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<String> lst = res.getValues("sample.aaa");
    EQUAL(lst.size(), 0);

    lst = res.getValues("sample.body.a(id=a4)");
    EQUAL(lst.size(), 0);
  }

  public void getValues_4()
  {
    MSG("キーに*が含まれている場合");
    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<String> lst = res.getValues("sample.body.*");
    EQUAL(lst.size(), 7);
    EQUAL(lst.get(0), "あ");
    EQUAL(lst.get(1), "び");
    EQUAL(lst.get(2), "びび");
    EQUAL(lst.get(3), "");
    EQUAL(lst.get(4), "し");
    EQUAL(lst.get(5), "しし");
    EQUAL(lst.get(6), "\n   あい  う え    お\n          ");

    lst = res.getValues("sample.body.*(id=a1)");
    EQUAL(lst.size(), 1);
    EQUAL(lst.get(0), "あ");
    lst = res.getValues("sample.body.*(id=b1)");
    EQUAL(lst.size(), 1);
    EQUAL(lst.get(0), "び");
    lst = res.getValues("sample.body.*(id=c2)");
    EQUAL(lst.size(), 1);
    EQUAL(lst.get(0), "しし");
  }

  public void findOrCreateFirstElement()
  {
    MSG("通常の操作の場合");
    DefaultResource res = new DefaultResourceEx();
    load(res);

    Element e = res.findOrCreateFirstElement("sample.title");
    EQUAL(e.getName(), "title");
    EQUAL(e.getValue(), "タイトル");

    e = res.findOrCreateFirstElement("sample.header");
    EQUAL(e.getName(), "header");
    EQUAL(e.getValue(), null);

    e = res.findFirstElement("sample.header");
    EQUAL(e.getName(), "header");
    EQUAL(e.getValue(), null);
  }

  public void findOrCreateFirstElement_1()
  {
    MSG("キーが空文字列の場合");

    DefaultResource res = new DefaultResourceEx();
    EQUAL(res.findOrCreateFirstElement(""), res.getBaseElement());

    load(res);

    Element e = res.findOrCreateFirstElement("");
    EQUAL(e, res.getBaseElement());
    EQUAL(e.getValue(), null);
  }

  public void findOrCreateFirstElement_2()
  {
    MSG("キーが属性を含む場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    Element e = res.findOrCreateFirstElement("sample.body(type=typeA)");
    EQUAL(e.getName(), "body");
    EQUAL(e.getValue(), "本文。");

    e = res.findOrCreateFirstElement("sample.header(id=H)");
    EQUAL(e.getName(), "header");
    EQUAL(e.getValue(), null);

    e = res.findFirstElement("sample.header(id=H)");
    EQUAL(e.getName(), "header");
    EQUAL(e.getValue(), null);
  }

  public void findOrCreateFirstElement_3()
  {
    MSG("キーが不正な場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    try {
      Element e = res.findOrCreateFirstElement("sample.");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void setFirstValue()
  {
    MSG("通常の場合");

    DefaultResource res = new DefaultResourceEx();
    EQUAL(res.getFirstValue("sample.aaa"), "");

    res.setFirstValue("sample.aaa", "あいうえお");
    EQUAL(res.getFirstValue("sample.aaa"), "あいうえお");

    res.setFirstValue("sample.aaa", "   あい  うえ    お");
    EQUAL(res.getFirstValue("sample.aaa"),  "   あい  うえ    お");

    res.setFirstValue("sample.aaa", "");
    EQUAL(res.getFirstValue("sample.aaa"), "");

    res.removeChildren("sample");
    load(res);

    EQUAL(res.getFirstValue("sample.title"), "タイトル");
    res.setFirstValue("sample.title", "あかさたな");
    EQUAL(res.getFirstValue("sample.title"), "あかさたな");
    res.setFirstValue("sample.title", "");
    EQUAL(res.getFirstValue("sample.title"), "");
  }

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

    DefaultResource res = new DefaultResourceEx();
    try {
      res.setFirstValue(null, null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.setFirstValue(null, "あいうえお");
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.setFirstValue("sample.aaa", null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void setFirstValue_1()
  {
    MSG("引数が空の場合");

    DefaultResource res = new DefaultResourceEx();
    EQUAL(res.getFirstValue(""), "");

    try {
      res.setFirstValue("", "あいうえお");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    EQUAL(res.getFirstValue(""), "");
  }

  public void setFirstValue_2()
  {
    MSG("引数が不正の場合");

    DefaultResource res = new DefaultResourceEx();

    try {
      res.setFirstValue("aaa.", "xyz");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.setFirstValue("aaa.bbb(X=", "あいうえお");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void setFirstValue_3()
  {
    MSG("複数の要素が該当するキーの場合");

    DefaultResource res = new DefaultResourceEx();
    
    res.setFirstValue("aaa.bbb(x=0)", "XXX");
    EQUAL(res.getFirstValue("aaa.bbb"), "XXX");

    res.setFirstValue("aaa.bbb(x=1)", "YYY");
    EQUAL(res.getFirstValue("aaa.bbb"), "XXX");

    res.setFirstValue("aaa.bbb(x=2)", "ZZZ");
    EQUAL(res.getFirstValue("aaa.bbb"), "XXX");

    res.setFirstValue("aaa.bbb", "ABC");
    EQUAL(res.getFirstValue("aaa.bbb"), "ABC");
  }

  public void removeChildren()
  {
    MSG("通常の操作の場合");

    DefaultResource res = new DefaultResourceEx();
    EQUAL(res.getFirstValue("aaa.bbb"), "");
    EQUAL(res.getFirstChild("aaa.bbb"), Resource.EMPTY);

    res.setFirstValue("aaa.bbb", "あいうえお");
    EQUAL(res.getFirstValue("aaa.bbb"), "あいうえお");

    res.removeChildren("aaa.bbb");
    EQUAL(res.getFirstValue("aaa.bbb"), "");
    EQUAL(res.getFirstChild("aaa.bbb"), Resource.EMPTY);
  }

  public void removeChildren_1()
  {
    MSG("引数が空文字列の場合");

    DefaultResource res = new DefaultResourceEx();
    EQUAL(res.getFirstValue(""), "");
    EQUAL(((DefaultResource)res.getFirstChild("")).getBaseElement(),
      res.getRootElement());

    res.removeChildren("");
    EQUAL(res.getFirstValue(""), "");
    EQUAL(((DefaultResource)res.getFirstChild("")).getBaseElement(),
      res.getRootElement());

    res.setFirstValue("abc", "XXX");

    Resource child = res.getFirstChild("abc");
    NOTNULL(child);
    EQUAL(child.getFirstValue(""), "XXX");

    child.removeChildren("");
  }

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

    DefaultResource res = new DefaultResourceEx();
    try {
      res.removeChildren(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void removeChildren_3()
  {
    MSG("引数が不正な場合");

    DefaultResource res = new DefaultResourceEx();
    try {
      res.removeChildren("aaa.");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      res.removeChildren("aaa.bbb(X=");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void removeChildren_4()
  {
    MSG("複数の要素を削除する場合");

    DefaultResource res = new DefaultResourceEx();
    EQUAL(res.getFirstValue("aaa.bbb"), "");
    EQUAL(res.getFirstChild("aaa.bbb"), Resource.EMPTY);

    res.removeChildren("aaa.bbb");

    res.setFirstValue("aaa.bbb(X=1)", "あいうえお");
    res.setFirstValue("aaa.bbb(X=2)", "かきくけこ");
    res.setFirstValue("aaa.bbb(X=3)", "さしすせそ");
    EQUAL(res.getFirstValue("aaa.bbb"), "あいうえお");
    EQUAL(res.getFirstValue("aaa.bbb(X=1)"), "あいうえお");
    EQUAL(res.getFirstValue("aaa.bbb(X=2)"), "かきくけこ");
    EQUAL(res.getFirstValue("aaa.bbb(X=3)"), "さしすせそ");

    res.removeChildren("aaa.bbb");
    EQUAL(res.getFirstValue("aaa.bbb"), "");
    EQUAL(res.getFirstChild("aaa.bbb"), Resource.EMPTY);

    EQUAL(res.getFirstValue("aaa.bbb(X=1)"), "");
    EQUAL(res.getFirstValue("aaa.bbb(X=2)"), "");
    EQUAL(res.getFirstValue("aaa.bbb(X=3)"), "");
  }

  public void getFirstChild()
  {
    MSG("通常の操作");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.getFirstValue("sample.title"), "タイトル");
    EQUAL(res.getFirstValue("sample.body"), "本文。");
    EQUAL(res.getFirstValue("sample.body.a(id=a1,name=A1)"), "あ");
    EQUAL(res.getFirstValue("sample.body.b(id=b1,name=B1)"), "び");
    EQUAL(res.getFirstValue("sample.body.b(id=b2,name=B2)"), "びび");
    EQUAL(res.getFirstValue("sample.body.b(id=b3)"), "");

    DefaultResource child = (DefaultResource) res.getFirstChild("");
    EQUAL(child.getBaseElement(), res.getRootElement());
    EQUAL(child.getFirstValue("sample.title"), "タイトル");
    EQUAL(child.getFirstValue("sample.body"), "本文。");
    EQUAL(child.getFirstValue("sample.body.a(id=a1,name=A1)"), "あ");
    EQUAL(child.getFirstValue("sample.body.b(id=b1,name=B1)"), "び");
    EQUAL(child.getFirstValue("sample.body.b(id=b2,name=B2)"), "びび");
    EQUAL(child.getFirstValue("sample.body.b(id=b3)"), "");

    child = (DefaultResource) res.getFirstChild("sample");
    EQUAL(child.getBaseElement().getName(), "sample");
    EQUAL(child.getFirstValue("title"), "タイトル");
    EQUAL(child.getFirstValue("body"), "本文。");
    EQUAL(child.getFirstValue("body.a(id=a1,name=A1)"), "あ");
    EQUAL(child.getFirstValue("body.b(id=b1,name=B1)"), "び");
    EQUAL(child.getFirstValue("body.b(id=b2,name=B2)"), "びび");
    EQUAL(child.getFirstValue("body.b(id=b3)"), "");

    child = (DefaultResource) child.getFirstChild("body.b");
    EQUAL(child.getFirstValue(""), "び");
  }

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

    DefaultResource res = new DefaultResourceEx();
    try {
      res.getFirstChild(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void getFirstChild_2()
  {
    MSG("引数が不正の場合");

    DefaultResource res = new DefaultResourceEx();
    try {
      res.getFirstChild("aaa.");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      res.getFirstChild("aaa.bbb(X=");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void getFirstChild_3()
  {
    MSG("存在しないキーを指定した場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.getFirstChild("sample.label"), Resource.EMPTY);
    EQUAL(res.getFirstChild("sample.body.b(id=A1)"), Resource.EMPTY);
  }

  public void getFirstChild_4()
  {
    MSG("キーに*が存在する場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    Resource child = res.getFirstChild("*");
    EQUAL(child.getBaseElementName(), "sample");

    child = res.getFirstChild("sample.*");
    EQUAL(child.getBaseElementName(), "title");

    child = res.getFirstChild("sample.body.*");
    EQUAL(child.getBaseElementName(), "a");

    child = res.getFirstChild("sample.body");
    child = child.getFirstChild("*");
    EQUAL(child.getBaseElementName(), "a");

    child = res.getFirstChild("sample");
    child = child.getFirstChild("*.*(id=b2)");
    EQUAL(child.getBaseElementName(), "b");
    EQUAL(child.getFirstValue(""), "びび");
  }

  public void getChildren()
  {
    MSG("通常の操作");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<Resource> children = res.getChildren("");
    EQUAL(children.size(), 1);
    EQUAL(((DefaultResource)children.get(0)).getBaseElement(),
      res.getRootElement());

    children = res.getChildren("sample.title");
    EQUAL(children.size(), 1);
    EQUAL(children.get(0).getFirstValue(""), "タイトル");

    children = res.getChildren("sample.body.b");
    EQUAL(children.size(), 3);
    EQUAL(children.get(0).getFirstValue(""), "び");
    EQUAL(children.get(1).getFirstValue(""), "びび");
    EQUAL(children.get(2).getFirstValue(""), "");

    children = res.getChildren("sample.body.b(id=b2)");
    EQUAL(children.size(), 1);
    EQUAL(children.get(0).getFirstValue(""), "びび");
  }

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

    DefaultResource res = new DefaultResourceEx();
    try {
      res.getChildren(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void getChildren_2()
  {
    MSG("引数が不正な場合");

    DefaultResource res = new DefaultResourceEx();
    try {
      res.getChildren("sample.aaa.");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.getChildren("sample.bbb(id=");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void getChildren_3()
  {
    MSG("存在しないキーを指定した場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.getChildren("sample.label").size(), 0);
    EQUAL(res.getChildren("sample.body.b(id=A1)").size(), 0);
  }

  public void getChildren_4()
  {
    MSG("キーに*が含まれている場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<Resource> resL = res.getChildren("*");
    EQUAL(resL.size(), 1);
    EQUAL(resL.get(0).getBaseElementName(), "sample");

    resL = res.getChildren("sample.*");
    EQUAL(resL.size(), 2);
    EQUAL(resL.get(0).getBaseElementName(), "title");
    EQUAL(resL.get(1).getBaseElementName(), "body");

    resL = res.getChildren("sample.body.*");
    EQUAL(resL.size(), 7);
    EQUAL(resL.get(0).getBaseElementName(), "a");
    EQUAL(resL.get(1).getBaseElementName(), "b");
    EQUAL(resL.get(2).getBaseElementName(), "b");
    EQUAL(resL.get(3).getBaseElementName(), "b");
    EQUAL(resL.get(4).getBaseElementName(), "c");
    EQUAL(resL.get(5).getBaseElementName(), "c");
    EQUAL(resL.get(6).getBaseElementName(), "c");

    resL = res.getChildren("sample.body.*(id=a1)");
    EQUAL(resL.size(), 1);
    EQUAL(resL.get(0).getBaseElementName(), "a");

    resL = res.getChildren("sample.body.*(id=b1)");
    EQUAL(resL.size(), 1);
    EQUAL(resL.get(0).getBaseElementName(), "b");

    resL = res.getChildren("sample.body.*(id=c1)");
    EQUAL(resL.size(), 1);
    EQUAL(resL.get(0).getBaseElementName(), "c");
  }

  public void getOrCreateFirstChild()
  {
    MSG("存在するキーを指定した場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    DefaultResource c = (DefaultResource)
      res.getOrCreateFirstChild("sample.body.a");
    List<Resource> l = res.getChildren("sample.body.a");
    EQUAL(l.size(), 1);
    EQUAL(c.getBaseElement(), ((DefaultResource)l.get(0)).getBaseElement());
  }

  public void getOrCreateFirstChild_1()
  {
    MSG("存在しないキーを指定した場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<Resource> bL = res.getChildren("sample.header.label");
    EQUAL(bL.size(), 0);

    DefaultResource a = (DefaultResource) res.getOrCreateFirstChild(
      "sample.header.label");
    EQUAL(a.getFirstValue(""), "");

    List<Resource> aL = res.getChildren("sample.header.label");
    EQUAL(aL.size(), 1);
    EQUAL(a.getBaseElement(), ((DefaultResource)aL.get(0)).getBaseElement());
  }

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

    DefaultResource res = new DefaultResourceEx();
    try {
      res.getOrCreateFirstChild(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void getOrCreateFirstChild_3()
  {
    MSG("引数が不正な場合");
    
    DefaultResource res = new DefaultResourceEx();
    try {
      res.getOrCreateFirstChild("sample.bbb.");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      res.getOrCreateFirstChild("sample.bbb(b=");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void getFirstAttribute()
  {
    MSG("通常の操作");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.getFirstAttribute("sample", "id"), "");
    EQUAL(res.getFirstAttribute("sample.body", "id"), "");
    EQUAL(res.getFirstAttribute("sample.body", "type"), "typeA");
    EQUAL(res.getFirstAttribute("sample.body.a", "id"), "a1");
    EQUAL(res.getFirstAttribute("sample.body.b", "id"), "b1");
    EQUAL(res.getFirstAttribute("sample.body.c", "id"), "c1");
    EQUAL(res.getFirstAttribute("sample.body.a(id=a1)", "name"), "A1");
    EQUAL(res.getFirstAttribute("sample.body.b(id=b2,name=B2)", "name"), "B2");
    EQUAL(res.getFirstAttribute("sample.body.c(name=C2)", "id"), "c2");
  }

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

    DefaultResource res = new DefaultResourceEx();
    load(res);

    try {
      res.getFirstAttribute(null, "id");
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      res.getFirstAttribute("sample.body.a", null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void getFirstAttribute_2()
  {
    MSG("属性名に空文字列を指定した場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.getFirstAttribute("sample", ""), "");
    EQUAL(res.getFirstAttribute("", "type"), "");

    Resource child = res.getFirstChild("sample.body");
    EQUAL(child.getFirstAttribute("", "type"), "typeA");
  }

  public void getFirstAttribute_3()
  {
    MSG("存在しない属性名を指定した場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.getFirstAttribute("sample.body", "typeB"), "");
    EQUAL(res.getFirstAttribute("sample.body(type=typeB)", "type"), "");
  }

  public void getAttributes()
  {
    MSG("通常の操作");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<String> attrLst = null;
    attrLst = res.getAttributes("sample", "id");
    EQUAL(attrLst.size(), 1);
    EQUAL(attrLst.get(0), "");

    attrLst = res.getAttributes("sample.body", "id");
    EQUAL(attrLst.size(), 1);
    EQUAL(attrLst.get(0), "");

    attrLst = res.getAttributes("sample.body", "type");
    EQUAL(attrLst.size(), 1);
    EQUAL(attrLst.get(0), "typeA");

    attrLst = res.getAttributes("sample.body.a", "id");
    EQUAL(attrLst.size(), 1);
    EQUAL(attrLst.get(0), "a1");

    attrLst = res.getAttributes("sample.body.b", "id");
    EQUAL(attrLst.size(), 3);
    EQUAL(attrLst.get(0), "b1");
    EQUAL(attrLst.get(1), "b2");
    EQUAL(attrLst.get(2), "b3");

    attrLst = res.getAttributes("sample.body.b", "name");
    EQUAL(attrLst.size(), 3);
    EQUAL(attrLst.get(0), "B1");
    EQUAL(attrLst.get(1), "B2");
    EQUAL(attrLst.get(2), "");

    attrLst = res.getAttributes("sample.body.b(id=b3)", "name");
    EQUAL(attrLst.size(), 1);
    EQUAL(attrLst.get(0), "");

    attrLst = res.getAttributes("sample.body.c", "id");
    EQUAL(attrLst.size(), 3);
    EQUAL(attrLst.get(0), "c1");
    EQUAL(attrLst.get(1), "c2");
    EQUAL(attrLst.get(2), "c3");

    attrLst = res.getAttributes("sample.body.c(id=c2,name=C2)", "name");
    EQUAL(attrLst.size(), 1);
    EQUAL(attrLst.get(0), "C2");
  }

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

    DefaultResource res = new DefaultResourceEx();
    load(res);

    try {
      res.getAttributes(null, "id");
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      res.getAttributes("sample.body.a", null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void getAttributes_2()
  {
    MSG("引数に空文字列を指定した場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    List<String> attrLst = null;

    attrLst = res.getAttributes("", "type");
    EQUAL(attrLst.size(), 1);
    EQUAL(attrLst.get(0), "");

    attrLst = res.getAttributes("sample", "");
    EQUAL(attrLst.size(), 1);
    EQUAL(attrLst.get(0), "");

    attrLst = res.getAttributes("sample(id=)", "");
    EQUAL(attrLst.size(), 0);

    Resource child = res.getFirstChild("sample.body");
    attrLst = child.getAttributes("", "type");
    EQUAL(attrLst.size(), 1);
    EQUAL(attrLst.get(0), "typeA");

    child = res.getFirstChild("sample.body.b");
    attrLst = child.getAttributes("", "name");
    EQUAL(attrLst.size(), 1);
    EQUAL(attrLst.get(0), "B1");
  }

  public void getAttributes_3()
  {
    MSG("存在しない属性名を指定した場合");

    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.getAttributes("sample.body(type=typeB)", "type").size(), 0);

    List<String> attrs = res.getAttributes("sample.body.b", "type");
    EQUAL(attrs.size(), 3);
    EQUAL(attrs.get(0), "");
    EQUAL(attrs.get(1), "");
    EQUAL(attrs.get(2), "");

    List<String> attrs2 = res.getAttributes("sample.title", "type");
    EQUAL(attrs2.size(), 1);
    EQUAL(attrs2.get(0), "");
  }

  public void renew()
  {
    DefaultResource res = new DefaultResourceEx();
    load(res);

    EQUAL(res.findFirstElement("").getValue(), null);
    EQUAL(res.findFirstElement("sample.title").getValue(), "タイトル");
    EQUAL(res.findFirstElement("sample.body").getValue(), "本文。");
    EQUAL(res.findFirstElement("sample.body.a").getValue(), "あ");
    EQUAL(res.findFirstElement("sample.body.b").getValue(), "び");
    EQUAL(res.findFirstElement("sample.body.c").getValue(), "し");

    Element base = res.getBaseElement();
    Element root = res.getRootElement();

    res.renew();

    NULL(res.findFirstElement("sample.title"));
    NULL(res.findFirstElement("sample.body"));
    NULL(res.findFirstElement("sample.body.a"));
    NULL(res.findFirstElement("sample.body.b"));
    NULL(res.findFirstElement("sample.body.c"));

    FALSE(res.getBaseElement().equals(base));
    FALSE(res.getRootElement().equals(root));
  }
}
