/*
 * AbstractResourceTest 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 java.io.*;
import java.util.*;

/**
 * <code>AbstractResource</code>クラスの機能試験クラス。
 *
 * @author  佐藤隆之. 
 * @version $Revision: 1.2 $, $Date: 2011-05-30 12:33:57 $
 */
public class AbstractResourceTest extends FunctionTester
{
  public static void main(String[] args)
  {
    try {
      PrinterGroup group = new PrinterGroup();
      group.addPrinter(new HtmlPrinter("SATOH Takayuki"));
      group.addPrinter(new ConsolePrinter());
      setPrinter(group);

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

  class ResourceEx extends AbstractResource
  {
    public ResourceEx() {}
    public ResourceEx(ResourceEx res) { super(res); }
    public String getFirstValue(String key) { return ""; }
    public List<String> getValues(String key) { return null; }
    public String getFirstAttribute(String key, String attr) { return ""; }
    public List<String> getAttributes(String key, String attr) { return null; }
    public Resource getFirstChild(String key) { return Resource.EMPTY; }
    public List<Resource> getChildren(String key) { return null; } 
    public void setFirstValue(String key, String value) {}
    public Resource getOrCreateFirstChild(String key) { return Resource.EMPTY; }
    public void removeChildren(String key) {}
    public String getBaseElementName() { return ""; }
    protected void load(InputStream stream) throws IOException {}
    protected void save(OutputStream stream) throws IOException {}
  }

  /* -- test case -- */

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

    AbstractResource res = new ResourceEx();
    EQUAL(res.getElementSeparator(), '.');
    EQUAL(res.getAttributeParenthesis()[0], '(');
    EQUAL(res.getAttributeParenthesis()[1], ')');
    EQUAL(res.getAttributeSeparator(), ',');
    EQUAL(res.getAttributeMatchMark(), '=');
    EQUAL(res.getPath(), null);
  }

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

    AbstractResource res = new ResourceEx();
    EQUAL(res.elementSeparator(), ".");
    EQUAL(res.attributeParenthesis()[0], "(");
    EQUAL(res.attributeParenthesis()[1], ")");
    EQUAL(res.attributeSeparator(), ",");
    EQUAL(res.attributeMatchMark(), "=");
    EQUAL(res.getPath(), null);
    NOTNULL(res);
  }

  @Deprecated
  public void setElementSeparator()
  {
    MSG("キー要素セパレータを設定するメソッドの確認。");

    AbstractResource res = new ResourceEx();
    EQUAL(res.getElementSeparator(), '.');

    res.setElementSeparator('/');
    EQUAL(res.getElementSeparator(), '/');
  }

  public void setElementSeparator_str()
  {
    MSG("キー要素セパレータを設定するメソッドの確認。");

    AbstractResource res = new ResourceEx();
    EQUAL(res.elementSeparator(), ".");

    res.setElementSeparator("/");
    EQUAL(res.elementSeparator(), "/");

    res.setElementSeparator("\uD800\uDC33");
    EQUAL(res.elementSeparator(), "\uD800\uDC33");

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

    try {
      res.setElementSeparator("");
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    }

    try {
      res.setElementSeparator("//");
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    }
  }

  @Deprecated
  public void setAttributeParenthesis()
  {
    MSG("キー属性を囲む括弧を設定するメソッドの確認。");

    AbstractResource res = new ResourceEx();
    EQUAL(res.getAttributeParenthesis()[0], '(');
    EQUAL(res.getAttributeParenthesis()[1], ')');

    res.setAttributeParenthesis('[', ']');
    EQUAL(res.getAttributeParenthesis()[0], '[');
    EQUAL(res.getAttributeParenthesis()[1], ']');
  }

  public void setAttributeParenthesis_str()
  {
    MSG("キー属性を囲む括弧を設定するメソッドの確認。");

    AbstractResource res = new ResourceEx();
    EQUAL(res.attributeParenthesis()[0], "(");
    EQUAL(res.attributeParenthesis()[1], ")");

    res.setAttributeParenthesis("[", "]");
    EQUAL(res.attributeParenthesis()[0], "[");
    EQUAL(res.attributeParenthesis()[1], "]");

    res.setAttributeParenthesis("\uD800\uDC32", "\uD800\uDC33");
    EQUAL(res.attributeParenthesis()[0], "\uD800\uDC32");
    EQUAL(res.attributeParenthesis()[1], "\uD800\uDC33");

    try {
      res.setAttributeParenthesis(null, ")");
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
    try {
      res.setAttributeParenthesis("(", null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
    try {
      res.setAttributeParenthesis("", ")");
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    }
    try {
      res.setAttributeParenthesis("(", "");
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    }
    try {
      res.setAttributeParenthesis("((", ")");
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    }
    try {
      res.setAttributeParenthesis("(", "))");
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    }
  }

  @Deprecated
  public void setAttributeSeparator()
  {
    MSG("キー属性のセパレータを設定するメソッドの確認。");

    AbstractResource res = new ResourceEx();
    EQUAL(res.getAttributeSeparator(), ',');

    res.setAttributeSeparator('|');
    EQUAL(res.getAttributeSeparator(), '|');
  }

  public void setAttributeSeparator_str()
  {
    MSG("キー属性のセパレータを設定するメソッドの確認。");

    AbstractResource res = new ResourceEx();
    EQUAL(res.attributeSeparator(), ",");

    res.setAttributeSeparator("|");
    EQUAL(res.attributeSeparator(), "|");

    res.setAttributeSeparator("\uD800\uDC32");
    EQUAL(res.attributeSeparator(), "\uD800\uDC32");

    try {
      res.setAttributeSeparator(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
    try {
      res.setAttributeSeparator("");
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    }
    try {
      res.setAttributeSeparator("||");
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    }
  }

  @Deprecated
  public void setAttributeMatchMark()
  {
    MSG("キー属性の名前と値の対応マークを設定するメソッドの確認。");

    AbstractResource res = new ResourceEx();
    EQUAL(res.getAttributeMatchMark(), '=');

    res.setAttributeMatchMark(':');
    EQUAL(res.getAttributeMatchMark(), ':');
  }

  public void setAttributeMatchMark_str()
  {
    MSG("キー属性の名前と値の対応マークを設定するメソッドの確認。");

    AbstractResource res = new ResourceEx();
    EQUAL(res.attributeMatchMark(), "=");

    res.setAttributeMatchMark(":");
    EQUAL(res.attributeMatchMark(), ":");

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

    try {
      res.setAttributeMatchMark("");
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    }

    try {
      res.setAttributeMatchMark(":=");
      NG();
    } catch (IllegalArgumentException e) {
      OK(e);
    }
  }

  public void splitKey()
  {
    MSG("キーを要素に分離するメソッドの確認。");

    AbstractResource res = new ResourceEx();
    try {
      List<String> lst = res.splitKey("a");
      EQUAL(lst.size(), 1);
      EQUAL(lst.get(0), "a");
    } catch (Exception e) {
      NG(e);
    }

    try {
      List<String> lst0 = res.splitKey("aaa.bbb.ccc");
      EQUAL(lst0.size(), 3);
      EQUAL(lst0.get(0), "aaa");
      EQUAL(lst0.get(1), "bbb");
      EQUAL(lst0.get(2), "ccc");
    } catch (Exception e) {
      NG(e);
    }

    try {
      List<String> lst3 = res.splitKey("aaa(bbb=ccc)");
      EQUAL(lst3.size(), 1);
      EQUAL(lst3.get(0), "aaa(bbb=ccc)");
    } catch (Exception e) {
      NG(e);
    }
    try {
      List<String> lst3 = res.splitKey("aaa(bbb=ccc,ddd=eee,fff=ggg)");
      EQUAL(lst3.size(), 1);
      EQUAL(lst3.get(0), "aaa(bbb=ccc,ddd=eee,fff=ggg)");
    } catch (Exception e) {
      NG(e);
    }

    try {
      List<String> lst3 = res.splitKey("aaa.bbb(Y=2).ccc");
      EQUAL(lst3.size(), 3);
      EQUAL(lst3.get(0), "aaa");
      EQUAL(lst3.get(1), "bbb(Y=2)");
      EQUAL(lst3.get(2), "ccc");
    } catch (Exception e) {
      NG(e);
    }

    try {
      List<String> lst4 = res.splitKey("aaa.bbb.ccc(Z=3)");
      EQUAL(lst4.size(), 3);
      EQUAL(lst4.get(0), "aaa");
      EQUAL(lst4.get(1), "bbb");
      EQUAL(lst4.get(2), "ccc(Z=3)");
    } catch (Exception e) {
      NG(e);
    }
  
    try {
      List<String> lst5 = res.splitKey("aaa(X=1,Y=2,Z=3).bbb.ccc");
      EQUAL(lst5.size(), 3);
      EQUAL(lst5.get(0), "aaa(X=1,Y=2,Z=3)");
      EQUAL(lst5.get(1), "bbb");
      EQUAL(lst5.get(2), "ccc");
    } catch (Exception e) {
      NG(e);
    }

    try {
      List<String> lst5 = res.splitKey("bbb.aaa(X=1,Y=2,Z=3)");
      EQUAL(lst5.size(), 2);
      EQUAL(lst5.get(0), "bbb");
      EQUAL(lst5.get(1), "aaa(X=1,Y=2,Z=3)");
    } catch (Exception e) {
      NG(e);
    }

    try {
      List<String> lst6 = res.splitKey("aaa.bb)X=1.ccc");
      EQUAL(lst6.size(), 3);
      EQUAL(lst6.get(0), "aaa");
      EQUAL(lst6.get(1), "bb)X=1");
      EQUAL(lst6.get(2), "ccc");
    } catch (Exception e) {
      NG(e);
    }
  }

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

    AbstractResource res = new ResourceEx();
    try {
      List<String> lst0 = res.splitKey(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

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

    AbstractResource res = new ResourceEx();
    try {
      List<String> lst = res.splitKey("");
      EQUAL(lst.size(), 0);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void splitKey_3()
  {
    MSG("要素が閉じ括弧で終了してない場合");

    AbstractResource res = new ResourceEx();
    try {
      res.splitKey("aaa.bb(X=1)b.ccc");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.splitKey("aaa.bb(X=1)b");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void splitKey_5()
  {
    MSG("属性の括弧が開いたまま要素が終了する場合");

    AbstractResource res = new ResourceEx();
    try {
      res.splitKey("aaa.bb(X=1.ccc");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.splitKey("aaa.bb(X=1");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void splitKey_6()
  {
    MSG("要素名が空の場合");

    AbstractResource res = new ResourceEx();
    try {
      res.splitKey("a.");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

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

    try {
      res.splitKey("aaa..ccc");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

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

    try {
      res.splitKey(".aaa.bbb");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.splitKey("aaa.(X=1)");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void splitKey_7()
  {
    MSG("属性名が空の場合");

    AbstractResource res = new ResourceEx();
    try {
      res.splitKey("aaa.bbb(=111).ccc");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      res.splitKey("aaa.bbb(=111)");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.splitKey("aaa.bbb().ccc");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      res.splitKey("aaa.bbb()");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.splitKey("aaa.bbb(=).ccc");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      res.splitKey("aaa.bbb(=)");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.splitKey("aaa.bbb(X=1,=2).ccc");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      res.splitKey("aaa.bbb(X=1,=2)");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.splitKey("aaa.bbb(X=1,).ccc");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      res.splitKey("aaa.bbb(X=1,)");
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.splitKey("aaa.bbb(,X=1).ccc");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      res.splitKey("aaa.bbb(,X=1)");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void splitKey_8()
  {
    MSG("属性に複数の等号が含まれている場合");

    AbstractResource res = new ResourceEx();
    try {
      List<String> lst = res.splitKey("aaa.bbb(X=1=2,Y==,Z==1=).ccc");
      EQUAL(lst.size(), 3);
      EQUAL(lst.get(0), "aaa");
      EQUAL(lst.get(1), "bbb(X=1=2,Y==,Z==1=)");
      EQUAL(lst.get(2), "ccc");
    } catch (Exception e) {
      NG(e);
    }
  }

  public void splitKey_9()
  {
    MSG("属性に等号が一つも含まれていない場合");

    AbstractResource res = new ResourceEx();
    try {
      res.splitKey("aaa.bbb(XXX-111).ccc");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      res.splitKey("aaa.bbb(X=1,Y,)");
      NG();
    } catch (IllegalKeyException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void getNameOfKeyElement()
  {
    MSG("キー要素から要素名を取得するメソッドの確認。");
    MSG("引数のキーが属性を含まない場合");

    AbstractResource res = new ResourceEx();
    EQUAL(res.getNameOfKeyElement("a"), "a");
    EQUAL(res.getNameOfKeyElement("aaa"), "aaa");
  }

  public void getNameOfKeyElement_1()
  {
    MSG("引数のキーが属性を含んでいる場合");

    AbstractResource res = new ResourceEx();
    EQUAL(res.getNameOfKeyElement("a(b=1)"), "a");
    EQUAL(res.getNameOfKeyElement("xyz(X=1,Y=2,Z=3)"), "xyz");
  }

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

    AbstractResource res = new ResourceEx();
    try {
      res.getNameOfKeyElement(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

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

    AbstractResource res = new ResourceEx();
    EQUAL(res.getNameOfKeyElement(""), "");
  }

  public void listAttributesOfKeyElement()
  {
    MSG("キー要素から属性のリストを取得するメソッドの確認。");
    MSG("引数が空文字の場合");

    AbstractResource res = new ResourceEx();
    List<String[]> lst = res.listAttributesOfKeyElement("");
    EQUAL(lst.size(), 0);
  }

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

    AbstractResource res = new ResourceEx();
    try {
      List<String[]> lst = res.listAttributesOfKeyElement(null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void listAttributesOfKeyElement_2()
  {
    MSG("属性を持たない要素の場合");

    AbstractResource res = new ResourceEx();
    List<String[]> lst0 = res.listAttributesOfKeyElement("aaa");
    EQUAL(lst0.size(), 0);

    List<String[]> lst1 = res.listAttributesOfKeyElement("abc)");
    EQUAL(lst1.size(), 0);

    List<String[]> lst2 = res.listAttributesOfKeyElement("ab=c)");
    EQUAL(lst2.size(), 0);

    List<String[]> lst3 = res.listAttributesOfKeyElement("ab=c,d)");
    EQUAL(lst3.size(), 0);
  }

  public void listAttributesOfKeyElement_3()
  {
    MSG("属性を持つ要素の場合");

    AbstractResource res = new ResourceEx();
    List<String[]> lst0 = res.listAttributesOfKeyElement("aaa(X=1)");
    EQUAL(lst0.size(), 1);
    EQUAL(lst0.get(0)[0], "X");
    EQUAL(lst0.get(0)[1], "1");

    List<String[]> lst1 = res.listAttributesOfKeyElement("aaa(X=1,Y=2)");
    EQUAL(lst1.size(), 2);
    EQUAL(lst1.get(0)[0], "X");
    EQUAL(lst1.get(0)[1], "1");
    EQUAL(lst1.get(1)[0], "Y");
    EQUAL(lst1.get(1)[1], "2");

    List<String[]> lst2 = res.listAttributesOfKeyElement("aaa(X=1,Y=2,Z=3)");
    EQUAL(lst2.size(), 3);
    EQUAL(lst2.get(0)[0], "X");
    EQUAL(lst2.get(0)[1], "1");
    EQUAL(lst2.get(1)[0], "Y");
    EQUAL(lst2.get(1)[1], "2");
    EQUAL(lst2.get(2)[0], "Z");
    EQUAL(lst2.get(2)[1], "3");

    List<String[]> lst3 = res.listAttributesOfKeyElement("aaa(X=,Y=2)");
    EQUAL(lst3.size(), 2);
    EQUAL(lst3.get(0)[0], "X");
    EQUAL(lst3.get(0)[1], "");
    EQUAL(lst3.get(1)[0], "Y");
    EQUAL(lst3.get(1)[1], "2");

    List<String[]> lst4 = res.listAttributesOfKeyElement("aaa(X=1,Y=)");
    EQUAL(lst4.size(), 2);
    EQUAL(lst4.get(0)[0], "X");
    EQUAL(lst4.get(0)[1], "1");
    EQUAL(lst4.get(1)[0], "Y");
    EQUAL(lst4.get(1)[1], "");
  }

  @Deprecated
  public void copy_constructor()
  {
    MSG("コピーコンストラクタの確認。");

    ResourceEx res = new ResourceEx();
    res.setElementSeparator('/');
    res.setAttributeSeparator('|');
    res.setAttributeMatchMark(':');
    res.setAttributeParenthesis('[', ']');

    EQUAL(res.getElementSeparator(), '/');
    EQUAL(res.getAttributeSeparator(), '|');
    EQUAL(res.getAttributeMatchMark(), ':');
    EQUAL(res.getAttributeParenthesis()[0], '[');
    EQUAL(res.getAttributeParenthesis()[1], ']');

    ResourceEx res2 = new ResourceEx(res);

    EQUAL(res2.getElementSeparator(), '/');
    EQUAL(res2.getAttributeSeparator(), '|');
    EQUAL(res2.getAttributeMatchMark(), ':');
    EQUAL(res2.getAttributeParenthesis()[0], '[');
    EQUAL(res2.getAttributeParenthesis()[1], ']');
  }

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

  public void load_path()
  {
    MSG("リソースファイルをロードするメソッドの確認。");

    final String PATH =
      "test/data/ts/util/resource/PropertyResource/sample.txt";

    File file = new File(PATH);
    try {
      PrintWriter pw = new PrintWriter(
        new OutputStreamWriter(new FileOutputStream(file)));
      pw.println("HELLO!");
      pw.flush();
      pw.close();
    }
    catch (Exception e) {
      NG(e);
    }

    final StringBuilder buf = new StringBuilder();

    ResourceEx res = new ResourceEx() {
      @Override
      protected void load(InputStream in) throws java.io.IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        buf.append(br.readLine());
      }
    };

    try {
      res.load(PATH);
      EQUAL(buf.toString(), "HELLO!");
    }
    catch (Exception e) {
      NG(e);
    }

    try {
      res.load(PATH + "xxx");
      NG();
    }
    catch (IOException e) {
      OK(e);
    }

    file.delete();
  }

  public void save_path()
  {
    MSG("リソースファイルを保存するメソッドの確認。");

    final String PATH =
      "test/data/ts/util/resource/PropertyResource/sample.txt";

    ResourceEx res = new ResourceEx() {
      public void save(OutputStream out) throws IOException {
        PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
        pw.println("ABCDEFG");
        pw.flush();
      }
    };

    try {
      res.save(PATH);
    } catch (Exception e) {
      NG(e);
    }

    final StringBuilder buf = new StringBuilder();
    ResourceEx res2 = new ResourceEx() {
      @Override
      protected void load(InputStream in) throws java.io.IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        buf.append(br.readLine());
      }
    };
    try {
      res2.load(PATH);
      EQUAL(buf.toString(), "ABCDEFG");
    }
    catch (Exception e) {
      NG(e);
    }

    File file = new File(PATH);
    file.delete();
  }

  public void save_path_1()
  {
    MSG("保存中に例外が発生した場合。");

    ResourceEx res = new ResourceEx() {
      @Override protected OutputStream  getOutputStream(String path)
      throws IOException {
        return null;
      }
      @Override public void save(OutputStream out) throws IOException {
        throw new IOException("abcdefg");
      }
    };

    try {
      res.save("");
      NG();
    } catch (IOException e) {
      EQUAL(e.getMessage(), "abcdefg");
    }
  }
}
