/*
 * StringSequenceTest 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.text;

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

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

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

  /* -- test case -- */

  public void constructor_str()
  {
    MSG("文字列を引数にとるコンストラクタ。");

    ObjectInspector oi = new ObjectInspector(this);
    oi.expect("str_", "");
    oi.expect("codePointCount_", 0);
    oi.expect("charIndex_", 0);
    oi.expect("codePointIndex_", 0);
    oi.inspect(new StringSequence(""));

    oi.expect("str_", "abc");
    oi.expect("codePointCount_", 3);
    oi.expect("codeIndex_", 0);
    oi.expect("codePointIndex_", 0);
    oi.inspect(new StringSequence("abc"));

    String s = "\uD800\uDC32\uD800\uDC33";
    oi.expect("str_", s);
    oi.expect("codePointCount_", 2);
    oi.expect("codeIndex_", 0);
    oi.expect("codePointIndex_", 0);
    oi.inspect(new StringSequence(s));
  }

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

    try {
      new StringSequence((String)null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void constructor_str_index()
  {
    MSG("文字列と開始インデックスを引数にとるコンストラクタ。");

    ObjectInspector oi = new ObjectInspector(this);
    oi.expect("str_", "abc");
    oi.expect("charIndex_", 0);
    oi.expect("codePointIndex_", 0);
    oi.expect("codePointCount_", 3);
    oi.inspect(new StringSequence("abc", 0));

    oi.expect("str_", "abc");
    oi.expect("charIndex_", 1);
    oi.expect("codePointIndex_", 1);
    oi.expect("codePointCount_", 3);
    oi.inspect(new StringSequence("abc", 1));

    oi.expect("str_", "abc");
    oi.expect("charIndex_", 2);
    oi.expect("codePointIndex_", 2);
    oi.expect("codePointCount_", 3);
    oi.inspect(new StringSequence("abc", 2));

    oi.expect("str_", "abc");
    oi.expect("charIndex_", -1);
    oi.expect("codePointIndex_", -1);
    oi.expect("codePointCount_", 3);
    oi.inspect(new StringSequence("abc", -1));

    oi.expect("str_", "abc");
    oi.expect("charIndex_", 3);
    oi.expect("codePointIndex_", 3);
    oi.expect("codePointCount_", 3);
    oi.inspect(new StringSequence("abc", 3));

    oi.expect("str_", "");
    oi.expect("charIndex_", -1);
    oi.expect("codePointIndex_", -1);
    oi.expect("codePointCount_", 0);
    oi.inspect(new StringSequence("", -1));

    oi.expect("str_", "");
    oi.expect("charIndex_", 0);
    oi.expect("codePointIndex_", 0);
    oi.expect("codePointCount_", 0);
    oi.inspect(new StringSequence("", 0));
  }

  public void constructor_str_index_1()
  {
    MSG("インデックスが範囲外の場合。");

    try {
      new StringSequence("", -2);
      NG();
    } catch (IndexOutOfBoundsException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
    try {
      new StringSequence("", 1);
      NG();
    } catch (IndexOutOfBoundsException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      new StringSequence("abc", -2);
      NG();
    } catch (IndexOutOfBoundsException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    try {
      new StringSequence("abc", 4);
      NG();
    } catch (IndexOutOfBoundsException e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

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

    try {
      new StringSequence(null, 0);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void copy_constructor()
  {
    MSG("コピー・コンストラクタ。");

    ObjectInspector oi = new ObjectInspector(this);

    String str = "\uD800\uDC31\uD800\uDC32\uD800\uDC33";

    StringSequence seq1 = new StringSequence(str);
    StringSequence seq2 = new StringSequence(seq1);
    oi.expect("str_", "\uD800\uDC31\uD800\uDC32\uD800\uDC33");
    oi.expect("charIndex_", 0);
    oi.expect("codePointIndex_", 0);
    oi.expect("codePointCount_", 3);
    oi.inspect(seq1);
    oi.inspect(seq2);

    seq1.next();
    seq1.next();
    seq2 = new StringSequence(seq1);
    oi.expect("str_", "\uD800\uDC31\uD800\uDC32\uD800\uDC33");
    oi.expect("charIndex_", 4);
    oi.expect("codePointIndex_", 2);
    oi.expect("codePointCount_", 3);
    oi.inspect(seq1);
    oi.inspect(seq2);
  }

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

    try {
      new StringSequence((String) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
  }

  public void copy()
  {
    MSG("オブジェクトのコピー。");

    String str = "あいうえお";
    StringSequence seq1 = new StringSequence(str);
    StringSequence seq2 = seq1.copy();
    EQUAL(seq1.substring(), seq2.substring());
    EQUAL(seq1.index(), seq2.index());
    try {
      EQUAL(seq1.substring(seq2), "");
    } catch (IllegalArgumentException e) {
      NG(e);
    }

    seq1.next();
    seq1.next();
    EQUAL(seq1.substring(), "うえお");
    EQUAL(seq1.index(), 2);

    seq2 = seq1.copy();
    EQUAL(seq1.substring(), seq2.substring());
    EQUAL(seq1.substring(), seq2.substring());
    EQUAL(seq1.index(), seq2.index());
    try {
      EQUAL(seq1.substring(seq2), "");
    } catch (IllegalArgumentException e) {
      NG(e);
    }
  }

  public void validIndex()
  {
    MSG("インデックスが範囲内かどうかの判定。");

    StringSequence seq = new StringSequence("");
    FALSE(seq.validIndex());

    seq = new StringSequence("", -1);
    FALSE(seq.validIndex());

    seq = new StringSequence("abc", -1);
    FALSE(seq.validIndex());
    EQUAL(seq.index(), -1);
    seq.next();
    TRUE (seq.validIndex());
    EQUAL(seq.index(), 0);
    seq.next();
    TRUE (seq.validIndex());
    EQUAL(seq.index(), 1);
    seq.next();
    TRUE (seq.validIndex());
    EQUAL(seq.index(), 2);
    seq.next();
    FALSE(seq.validIndex());
    EQUAL(seq.index(), 3);

    seq = new StringSequence("\uD800\uDC33");
    EQUAL(StringOperation.length(seq.substring()), 1);
    TRUE (seq.validIndex());
    EQUAL(seq.index(), 0);
    seq.next();
    FALSE(seq.validIndex());
    EQUAL(seq.index(), 1);

    seq = new StringSequence("\uD800\uD800");
    EQUAL(StringOperation.length(seq.substring()), 2);
    TRUE (seq.validIndex());
    EQUAL(seq.index(), 0);
    seq.next();
    TRUE (seq.validIndex());
    EQUAL(seq.index(), 1);
    seq.next();
    FALSE(seq.validIndex());
    EQUAL(seq.index(), 2);

    seq = new StringSequence("\uDC33\uDC34");
    EQUAL(StringOperation.length(seq.substring()), 2);
    TRUE (seq.validIndex());
    EQUAL(seq.index(), 0);
    seq.next();
    TRUE (seq.validIndex());
    EQUAL(seq.index(), 1);
    seq.next();
    FALSE(seq.validIndex());
    EQUAL(seq.index(), 2);
  }

  public void hasNext()
  {
    MSG("後が存在するかどうかの判定。");

    StringSequence seq = new StringSequence("");
    FALSE(seq.hasNext());

    seq = new StringSequence("", -1);
    FALSE(seq.hasNext());

    seq = new StringSequence("", 0);
    FALSE(seq.hasNext());

    seq = new StringSequence("abc");
    TRUE(seq.hasNext());

    seq = new StringSequence("abc", -1);
    TRUE(seq.hasNext());

    seq = new StringSequence("abc", 0);
    TRUE(seq.hasNext());

    seq = new StringSequence("abc", 1);
    TRUE(seq.hasNext());

    seq = new StringSequence("abc", 2);
    FALSE(seq.hasNext());

    seq = new StringSequence("abc", 3);
    FALSE(seq.hasNext());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    TRUE(seq.hasNext());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    TRUE(seq.hasNext());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 0);
    TRUE(seq.hasNext());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 1);
    TRUE(seq.hasNext());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 2);
    FALSE(seq.hasNext());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 3);
    FALSE(seq.hasNext());
  }

  public void hasPrevious()
  {
    MSG("前が存在するかどうかの判定。");

    StringSequence seq = new StringSequence("");
    FALSE(seq.hasPrevious());

    seq = new StringSequence("abc", -1);
    FALSE(seq.hasPrevious());

    seq = new StringSequence("abc", 0);
    FALSE(seq.hasPrevious());

    seq = new StringSequence("abc", 1);
    TRUE(seq.hasPrevious());

    seq = new StringSequence("abc", 2);
    TRUE(seq.hasPrevious());

    seq = new StringSequence("abc", 3);
    TRUE(seq.hasPrevious());


    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    FALSE(seq.hasPrevious());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    FALSE(seq.hasPrevious());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 0);
    FALSE(seq.hasPrevious());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 1);
    TRUE(seq.hasPrevious());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 2);
    TRUE(seq.hasPrevious());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 3);
    TRUE(seq.hasPrevious());
  }

  public void next()
  {
    MSG("インデックスを次に進める。");

    StringSequence seq = new StringSequence("");

    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 0);
    FALSE(seq.hasNext());
    EQUAL(seq.next(), seq);;

    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 0);
    FALSE(seq.hasNext());
    EQUAL(seq.next(), seq);;

    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 0);
    FALSE(seq.hasNext());

    seq = new StringSequence("abc");
    EQUAL(seq.character(), "a");
    EQUAL(seq.index(), 0);
    TRUE(seq.hasNext());
    EQUAL(seq.next(), seq);;

    EQUAL(seq.character(), "b");
    EQUAL(seq.index(), 1);
    TRUE(seq.hasNext());
    EQUAL(seq.next(), seq);;

    EQUAL(seq.character(), "c");
    EQUAL(seq.index(), 2);
    FALSE(seq.hasNext());
    EQUAL(seq.next(), seq);;

    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 3);
    FALSE(seq.hasNext());
    EQUAL(seq.next(), seq);;

    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 3);
    FALSE(seq.hasNext());

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    EQUAL(seq.character(), "\uD800\uDC32");
    EQUAL(seq.index(), 0);
    TRUE(seq.hasNext());
    EQUAL(seq.next(), seq);;

    EQUAL(seq.character(), "\uD800\uDC33");
    EQUAL(seq.index(), 1);
    TRUE(seq.hasNext());
    EQUAL(seq.next(), seq);;

    EQUAL(seq.character(), "\uD800\uDC34");
    EQUAL(seq.index(), 2);
    FALSE(seq.hasNext());
    EQUAL(seq.next(), seq);;

    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 3);
    FALSE(seq.hasNext());
    EQUAL(seq.next(), seq);;

    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 3);
    FALSE(seq.hasNext());
    EQUAL(seq.next(), seq);;
  }

  public void next_1()
  {
    MSG("インデックスを-1から開始。");

    StringSequence seq = new StringSequence("", -1);
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), -1);

    seq.next();
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 0);

    seq.next();
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 0);

    seq = new StringSequence("abc", -1);
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), -1);

    seq.next();
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "a");
    EQUAL(seq.index(), 0);

    seq.next();
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "b");
    EQUAL(seq.index(), 1);

    seq.next();
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "c");
    EQUAL(seq.index(), 2);

    seq.next();
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 3);

    seq.next();
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 3);

    seq = new StringSequence("\uD800\uDC30\uD800\uDC31\uD800\uDC32", -1);
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), -1);

    seq.next();
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "\uD800\uDC30");
    EQUAL(seq.index(), 0);

    seq.next();
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "\uD800\uDC31");
    EQUAL(seq.index(), 1);

    seq.next();
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "\uD800\uDC32");
    EQUAL(seq.index(), 2);

    seq.next();
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 3);

    seq.next();
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 3);
  }

  public void next_count()
  {
    MSG("文字数を指定して次に進む。");

    StringSequence seq = new StringSequence("");
    seq.next(0);
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 0);

    seq = new StringSequence("");
    seq.next(1);
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 0);

    seq = new StringSequence("abc");
    seq.next(0);
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "a");
    EQUAL(seq.index(), 0);

    seq = new StringSequence("abc");
    seq.next(1);
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "b");
    EQUAL(seq.index(), 1);

    seq = new StringSequence("abc");
    seq.next(2);
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "c");
    EQUAL(seq.index(), 2);

    seq = new StringSequence("abc");
    seq.next(3);
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 3);

    seq.next(-1);
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "c");
    EQUAL(seq.index(), 2);

    seq.next(-1);
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "b");
    EQUAL(seq.index(), 1);

    seq.next(-1);
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "a");
    EQUAL(seq.index(), 0);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    TRUE(seq.hasNext());
    EQUAL(seq.index(), -1);
    seq.next(0);
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), -1);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    EQUAL(seq.index(), -1);
    seq.next(1);
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "\uD800\uDC32");
    EQUAL(seq.index(), 0);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    EQUAL(seq.index(), -1);
    seq.next(2);
    EQUAL(seq.character(), "\uD800\uDC33");
    EQUAL(seq.index(), 1);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    EQUAL(seq.index(), -1);
    seq.next(3);
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "\uD800\uDC34");
    EQUAL(seq.index(), 2);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    EQUAL(seq.index(), -1);
    seq.next(4);
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 3);

    seq.next(-1);
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "\uD800\uDC34");
    EQUAL(seq.index(), 2);

    seq.next(-1);
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "\uD800\uDC33");
    EQUAL(seq.index(), 1);

    seq.next(-1);
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "\uD800\uDC32");
    EQUAL(seq.index(), 0);
  }

  public void next_count_1()
  {
    MSG("インデックスが範囲外になる場合。");

    StringSequence seq = new StringSequence("");
    EQUAL(seq.index(), 0);
    seq.next(0);
    EQUAL(seq.index(), 0);

    seq = new StringSequence("abc");
    EQUAL(seq.index(), 0);
    seq.next(4);
    EQUAL(seq.index(), 3);

    seq = new StringSequence("abc");
    EQUAL(seq.index(), 0);
    seq.next(-2);
    EQUAL(seq.index(), -1);

    seq = new StringSequence("abc", 2);
    EQUAL(seq.index(), 2);
    seq.next(-3);
    EQUAL(seq.index(), -1);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    EQUAL(seq.index(), 0);
    seq.next(4);
    EQUAL(seq.index(), 3);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    EQUAL(seq.index(), 0);
    seq.next(-2);
    EQUAL(seq.index(), -1);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 3);
    EQUAL(seq.index(), 3);
    seq.next(1);
    EQUAL(seq.index(), 3);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 3);
    EQUAL(seq.index(), 3);
    seq.next(-4);
    EQUAL(seq.index(), -1);
  }

  public void previous()
  {
    MSG("インデックスを前に戻す。");

    String s = "abc";
    StringSequence seq = new StringSequence(s, 3);
    EQUAL(seq.index(), 3);
    EQUAL(seq.character(), "");
    TRUE (seq.hasPrevious());

    EQUAL(seq.previous(), seq);
    EQUAL(seq.index(), 2);
    EQUAL(seq.character(), "c");
    TRUE (seq.hasPrevious());

    EQUAL(seq.previous(), seq);
    EQUAL(seq.index(), 1);
    EQUAL(seq.character(), "b");
    TRUE (seq.hasPrevious());

    EQUAL(seq.previous(), seq);
    EQUAL(seq.index(), 0);
    EQUAL(seq.character(), "a");
    FALSE(seq.hasPrevious());

    EQUAL(seq.previous(), seq);
    EQUAL(seq.index(), -1);
    EQUAL(seq.character(), "");
    FALSE(seq.hasPrevious());

    EQUAL(seq.previous(), seq);
    EQUAL(seq.index(), -1);
    EQUAL(seq.character(), "");
    FALSE(seq.hasPrevious());

    s = "\uD800\uDC32\uD800\uDC33\uD800\uDC34";
    seq = new StringSequence(s, 3);
    EQUAL(seq.index(), 3);
    EQUAL(seq.character(), "");
    TRUE (seq.hasPrevious());

    EQUAL(seq.previous(), seq);
    EQUAL(seq.index(), 2);
    EQUAL(seq.character(), "\uD800\uDC34");
    TRUE (seq.hasPrevious());

    EQUAL(seq.previous(), seq);
    EQUAL(seq.index(), 1);
    EQUAL(seq.character(), "\uD800\uDC33");
    TRUE (seq.hasPrevious());

    EQUAL(seq.previous(), seq);
    EQUAL(seq.index(), 0);
    EQUAL(seq.character(), "\uD800\uDC32");
    FALSE(seq.hasPrevious());

    EQUAL(seq.previous(), seq);
    EQUAL(seq.index(), -1);
    EQUAL(seq.character(), "");
    FALSE(seq.hasPrevious());

    seq = new StringSequence("");
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), 0);
    EQUAL(seq.character(), "");

    EQUAL(seq.previous(), seq);
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), -1);
    EQUAL(seq.character(), "");
  }

  public void previous_count()
  {
    MSG("文字数を指定して前に戻す。");

    StringSequence seq = new StringSequence("", 0);
    seq.previous(0);
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), 0);
    EQUAL(seq.character(), "");

    seq = new StringSequence("", 0);
    seq.previous(1);
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), -1);
    EQUAL(seq.character(), "");

    seq = new StringSequence("", -1);
    seq.previous(0);
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), -1);
    EQUAL(seq.character(), "");

    seq = new StringSequence("abc", 3);
    seq.previous(0);
    TRUE(seq.hasPrevious());
    EQUAL(seq.index(), 3);
    EQUAL(seq.character(), "");

    seq = new StringSequence("abc", 3);
    seq.previous(1);
    TRUE(seq.hasPrevious());
    EQUAL(seq.index(), 2);
    EQUAL(seq.character(), "c");

    seq = new StringSequence("abc", 3);
    seq.previous(2);
    TRUE(seq.hasPrevious());
    EQUAL(seq.index(), 1);
    EQUAL(seq.character(), "b");

    seq = new StringSequence("abc", 3);
    seq.previous(3);
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), 0);
    EQUAL(seq.character(), "a");

    seq = new StringSequence("abc", 3);
    seq.previous(4);
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), -1);
    EQUAL(seq.character(), "");

    seq.previous(-1);
    EQUAL(seq.character(), "a");
    EQUAL(seq.index(), 0);
    seq.previous(-1);
    EQUAL(seq.character(), "b");
    EQUAL(seq.index(), 1);
    seq.previous(-1);
    EQUAL(seq.character(), "c");
    EQUAL(seq.index(), 2);
    seq.previous(-1);
    EQUAL(seq.character(), "");
    EQUAL(seq.index(), 3);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 3);
    seq.previous(0);
    TRUE (seq.hasPrevious());
    EQUAL(seq.index(), 3);
    EQUAL(seq.character(), "");

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 3);
    seq.previous(1);
    TRUE (seq.hasPrevious());
    EQUAL(seq.index(), 2);
    EQUAL(seq.character(), "\uD800\uDC34");

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 3);
    seq.previous(2);
    TRUE (seq.hasPrevious());
    EQUAL(seq.index(), 1);
    EQUAL(seq.character(), "\uD800\uDC33");

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 3);
    seq.previous(3);
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), 0);
    EQUAL(seq.character(), "\uD800\uDC32");

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", 3);
    seq.previous(4);
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), -1);
    EQUAL(seq.character(), "");

    seq.previous(-1);
    EQUAL(seq.index(), 0);
    EQUAL(seq.character(), "\uD800\uDC32");

    seq.previous(-1);
    EQUAL(seq.index(), 1);
    EQUAL(seq.character(), "\uD800\uDC33");

    seq.previous(-1);
    EQUAL(seq.index(), 2);
    EQUAL(seq.character(), "\uD800\uDC34");

    seq.previous(-1);
    EQUAL(seq.index(), 3);
    EQUAL(seq.character(), "");
  }

  public void previous_count_1()
  {
    MSG("インデックスが範囲外になる場合。");

    StringSequence seq = new StringSequence("");
    seq.previous(2);
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), -1);
    EQUAL(seq.character(), "");

    seq = new StringSequence("");
    seq.previous(-1);
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), 0);
    EQUAL(seq.character(), "");

    seq = new StringSequence("abc", 3);
    seq.previous(5);
    FALSE(seq.hasPrevious());
    EQUAL(seq.index(), -1);
    EQUAL(seq.character(), "");

    seq = new StringSequence("abc", 3);
    seq.previous(-1);
    TRUE (seq.hasPrevious());
    EQUAL(seq.index(), 3);
    EQUAL(seq.character(), "");
  }

  public void index()
  {
    String aStr = "abc";
    StringSequence seq = new StringSequence(aStr);
    int i=0;
    EQUAL(seq.index(), i);
    for ( ; seq.validIndex(); seq.next(), i++) {
      EQUAL(seq.index(), i);
    }
    EQUAL(seq.index(), StringOperation.length(aStr));

    aStr = "あ\uD800\uDC32い\uD800\uDC33";
    seq = new StringSequence(aStr);
    i = 0;
    EQUAL(seq.index(), i);
    for ( ; seq.validIndex(); seq.next(), i++) {
      EQUAL(seq.index(), i);
    }
    EQUAL(seq.index(), StringOperation.length(aStr));

    aStr = "";
    seq = new StringSequence(aStr);
    i = 0;
    EQUAL(seq.index(), i);
    for ( ; seq.validIndex(); seq.next(), i++) {
      EQUAL(seq.index(), i);
    }
    EQUAL(seq.index(), StringOperation.length(aStr));
  }

  public void index_1()
  {
    String aStr = "abc";
    StringSequence seq;
    int i;

    seq = new StringSequence(aStr, -1);
    i = -1;
    while (seq.hasNext()) {
      seq.next();
      i ++;
      EQUAL(seq.index(), i);
    }
    EQUAL(seq.next().index(), StringOperation.length(aStr));

    aStr = "あ\uD800\uDC32い\uD800\uDC33";
    seq = new StringSequence(aStr, -1);
    i = -1;
    while (seq.hasNext()) {
      seq.next();
      i ++;
      EQUAL(seq.index(), i);
    }
    EQUAL(seq.next().index(), StringOperation.length(aStr));

    aStr = "";
    seq = new StringSequence(aStr, -1);
    i = -1;
    while (seq.hasNext()) {
      seq.next();
      i ++;
      EQUAL(seq.index(), i);
    }
    EQUAL(seq.next().index(), StringOperation.length(aStr));
  }

  public void index_2()
  {
    String aStr = "abc";
    StringSequence seq;
    int i;

    if (! StringOperation.isEmpty(aStr)) {
      seq = new StringSequence(aStr, -1);
      i = -1;
      do {
        EQUAL(seq.index(), i);
        i ++;
      } while (seq.next().validIndex());
    }

    aStr = "あ\uD800\uDC32い\uD800\uDC33";
    if (! StringOperation.isEmpty(aStr)) {
      seq = new StringSequence(aStr, -1);
      i = -1;
      do {
        EQUAL(seq.index(), i);
        i++;
      } while (seq.next().validIndex());
    }

    aStr = "";
    if (! StringOperation.isEmpty(aStr)) {
      seq = new StringSequence(aStr, -1);
      i=-1;
      do {
        EQUAL(seq.index(), i);
        i ++;
      } while (seq.next().validIndex());
    }
  }

  public void character()
  {
    MSG("現在のインデックスの文字を取得。");

    StringSequence seq = new StringSequence("abc", -1);
    EQUAL(seq.character(), "");
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "");

    seq.next();
    EQUAL(seq.character(), "a");
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "a");

    seq.next();
    EQUAL(seq.character(), "b");
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "b");

    seq.next();
    EQUAL(seq.character(), "c");
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "c");

    seq.next();
    EQUAL(seq.character(), "");
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");

    seq.next();
    EQUAL(seq.character(), "");
    TRUE(seq.hasPrevious());
    EQUAL(seq.character(), "");

    seq.previous();
    EQUAL(seq.character(), "c");
    TRUE(seq.hasPrevious());
    EQUAL(seq.character(), "c");

    seq.previous();
    EQUAL(seq.character(), "b");
    TRUE(seq.hasPrevious());
    EQUAL(seq.character(), "b");

    seq.previous();
    EQUAL(seq.character(), "a");
    FALSE(seq.hasPrevious());
    EQUAL(seq.character(), "a");

    seq.previous();
    EQUAL(seq.character(), "");
    FALSE(seq.hasPrevious());
    EQUAL(seq.character(), "");

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    EQUAL(seq.character(), "");
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "");

    seq.next();
    EQUAL(seq.character(), "\uD800\uDC32");
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "\uD800\uDC32");

    seq.next();
    EQUAL(seq.character(), "\uD800\uDC33");
    TRUE(seq.hasNext());
    EQUAL(seq.character(), "\uD800\uDC33");

    seq.next();
    EQUAL(seq.character(), "\uD800\uDC34");
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "\uD800\uDC34");

    seq.next();
    EQUAL(seq.character(), "");
    FALSE(seq.hasNext());
    EQUAL(seq.character(), "");

    seq.next();
    EQUAL(seq.character(), "");
    TRUE(seq.hasPrevious());
    EQUAL(seq.character(), "");

    seq.previous();
    EQUAL(seq.character(), "\uD800\uDC34");
    TRUE(seq.hasPrevious());
    EQUAL(seq.character(), "\uD800\uDC34");

    seq.previous();
    EQUAL(seq.character(), "\uD800\uDC33");
    TRUE(seq.hasPrevious());
    EQUAL(seq.character(), "\uD800\uDC33");

    seq.previous();
    EQUAL(seq.character(), "\uD800\uDC32");
    FALSE(seq.hasPrevious());
    EQUAL(seq.character(), "\uD800\uDC32");

    seq.previous();
    EQUAL(seq.character(), "");
    FALSE(seq.hasPrevious());
    EQUAL(seq.character(), "");
  }

  public void character_1()
  {
    MSG("文字列が空文字列の場合。");

    StringSequence seq = new StringSequence("");
    EQUAL(seq.character(), "");

    seq = new StringSequence("", -1);
    EQUAL(seq.character(), "");
  }

  public void character_2()
  {
    MSG("不正な補助文字が含まれている場合。");

    StringSequence seq = new StringSequence("\uD800\uDC32\uD800\uD800\uDC34");
    EQUAL(seq.character(), "\uD800\uDC32");
    seq.next();
    EQUAL(seq.character(), "\uD800");
    seq.next();

    seq = new StringSequence("\uD800\uDC32\uDC33\uD801\uD802");
    EQUAL(seq.character(), "\uD800\uDC32");
    seq.next();
    EQUAL(seq.character(), "\uDC33");
    seq.next();
    EQUAL(seq.character(), "\uD801");
    seq.next();
    EQUAL(seq.character(), "\uD802");
  }

  public void substring()
  {
    MSG("現在のインデックスから開始する部分文字列を取得。");

    StringSequence seq = new StringSequence("", -1);
    EQUAL(seq.substring(), "");
    FALSE(seq.hasNext());
    EQUAL(seq.substring(), "");
    seq.next();
    EQUAL(seq.substring(), "");
    FALSE(seq.hasNext());
    EQUAL(seq.substring(), "");
    seq.next();
    EQUAL(seq.substring(), "");

    seq = new StringSequence("abc", -1);
    EQUAL(seq.substring(), "abc");
    TRUE(seq.hasNext());
    EQUAL(seq.substring(), "abc");
    seq.next();
    EQUAL(seq.substring(), "abc");
    TRUE(seq.hasNext());
    EQUAL(seq.substring(), "abc");
    seq.next();
    EQUAL(seq.substring(), "bc");
    TRUE(seq.hasNext());
    EQUAL(seq.substring(), "bc");
    seq.next();
    EQUAL(seq.substring(), "c");
    FALSE(seq.hasNext());
    EQUAL(seq.substring(), "c");
    seq.next();
    EQUAL(seq.substring(), "");
    FALSE(seq.hasNext());
    EQUAL(seq.substring(), "");
    seq.previous();
    EQUAL(seq.substring(), "c");
    TRUE(seq.hasPrevious());
    EQUAL(seq.substring(), "c");
    seq.previous();
    EQUAL(seq.substring(), "bc");
    TRUE(seq.hasPrevious());
    EQUAL(seq.substring(), "bc");
    seq.previous();
    EQUAL(seq.substring(), "abc");
    FALSE(seq.hasPrevious());
    EQUAL(seq.substring(), "abc");
    seq.previous();
    EQUAL(seq.substring(), "abc");

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    EQUAL(seq.substring(), "\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    TRUE(seq.hasNext());
    EQUAL(seq.substring(), "\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    seq.next();
    EQUAL(seq.substring(), "\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    TRUE(seq.hasNext());
    EQUAL(seq.substring(), "\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    seq.next();
    EQUAL(seq.substring(), "\uD800\uDC33\uD800\uDC34");
    TRUE(seq.hasNext());
    EQUAL(seq.substring(), "\uD800\uDC33\uD800\uDC34");
    seq.next();
    EQUAL(seq.substring(), "\uD800\uDC34");
    FALSE(seq.hasNext());
    EQUAL(seq.substring(), "\uD800\uDC34");
    seq.next();
    EQUAL(seq.substring(), "");
    TRUE(seq.hasPrevious());
    EQUAL(seq.substring(), "");
    seq.previous();
    EQUAL(seq.substring(), "\uD800\uDC34");
    TRUE(seq.hasPrevious());
    EQUAL(seq.substring(), "\uD800\uDC34");
    seq.previous();
    EQUAL(seq.substring(), "\uD800\uDC33\uD800\uDC34");
    TRUE(seq.hasPrevious());
    EQUAL(seq.substring(), "\uD800\uDC33\uD800\uDC34");
    seq.previous();
    EQUAL(seq.substring(), "\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    FALSE(seq.hasPrevious());
    EQUAL(seq.substring(), "\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    seq.previous();
    EQUAL(seq.substring(), "\uD800\uDC32\uD800\uDC33\uD800\uDC34");
  }

  public void substring_1()
  {
    MSG("文字列が空文字列の場合。");

    StringSequence seq = new StringSequence("");
    EQUAL(seq.substring(), "");

    seq = new StringSequence("", -1);
    EQUAL(seq.substring(), "");
  }

  public void substring_seq()
  {
    MSG("引数のStringSequenceまでの部分文字列を取得。");

    StringSequence seq = new StringSequence("");
    StringSequence seq2 = seq.copy();
    EQUAL(seq2.substring(seq), "");
    seq.next();
    EQUAL(seq2.substring(seq), "");

    seq = new StringSequence("あいうえお");
    seq2 = seq.copy();
    EQUAL(seq2.substring(seq), "");
    seq.next();
    EQUAL(seq2.substring(seq), "あ");
    seq.next();
    EQUAL(seq2.substring(seq), "あい");
    seq.next();
    EQUAL(seq2.substring(seq), "あいう");
    seq.next();
    EQUAL(seq2.substring(seq), "あいうえ");
    seq.next();
    EQUAL(seq2.substring(seq), "あいうえお");

    seq = new StringSequence("a\uD800\uDC82か\uD800\uDC33\uD800\uDC34");
    seq2 = seq.copy();
    EQUAL(seq2.substring(seq), "");
    seq.next();
    EQUAL(seq2.substring(seq), "a");
    seq.next();
    EQUAL(seq2.substring(seq), "a\uD800\uDC82");
    seq.next();
    EQUAL(seq2.substring(seq), "a\uD800\uDC82か");
    seq.next();
    EQUAL(seq2.substring(seq), "a\uD800\uDC82か\uD800\uDC33");
    seq.next();
    EQUAL(seq2.substring(seq), "a\uD800\uDC82か\uD800\uDC33\uD800\uDC34");
  }

  public void substring_seq_1()
  {
    MSG("開始インデックスが-1の場合。");

    StringSequence seq = new StringSequence("", -1);
    StringSequence seq2 = seq.copy();
    EQUAL(seq2.substring(seq), "");
    seq.next();
    EQUAL(seq2.substring(seq), "");
    seq.next();
    EQUAL(seq2.substring(seq), "");

    seq = new StringSequence("あいうえお", -1);
    seq2 = seq.copy();
    EQUAL(seq2.substring(seq), "");
    seq.next();
    EQUAL(seq2.substring(seq), "");
    seq.next();
    EQUAL(seq2.substring(seq), "あ");
    seq.next();
    EQUAL(seq2.substring(seq), "あい");
    seq.next();
    EQUAL(seq2.substring(seq), "あいう");
    seq.next();
    EQUAL(seq2.substring(seq), "あいうえ");
    seq.next();
    EQUAL(seq2.substring(seq), "あいうえお");

    seq2.next();
    EQUAL(seq2.substring(seq), "あいうえお");
    seq2.next();
    EQUAL(seq2.substring(seq), "いうえお");
    seq2.next();
    EQUAL(seq2.substring(seq), "うえお");
    seq2.next();
    EQUAL(seq2.substring(seq), "えお");
    seq2.next();
    EQUAL(seq2.substring(seq), "お");
    seq2.next();
    EQUAL(seq2.substring(seq), "");
    seq2.next();
    EQUAL(seq2.substring(seq), "");

    seq = new StringSequence("a\uD800\uDC82か\uD800\uDC33\uD800\uDC34", -1);
    seq2 = seq.copy();
    EQUAL(seq2.substring(seq), "");
    seq.next();
    EQUAL(seq2.substring(seq), "");
    seq.next();
    EQUAL(seq2.substring(seq), "a");
    seq.next();
    EQUAL(seq2.substring(seq), "a\uD800\uDC82");
    seq.next();
    EQUAL(seq2.substring(seq), "a\uD800\uDC82か");
    seq.next();
    EQUAL(seq2.substring(seq), "a\uD800\uDC82か\uD800\uDC33");
    seq.next();
    EQUAL(seq2.substring(seq), "a\uD800\uDC82か\uD800\uDC33\uD800\uDC34");

    seq2.next();
    EQUAL(seq2.substring(seq), "a\uD800\uDC82か\uD800\uDC33\uD800\uDC34");
    seq2.next();
    EQUAL(seq2.substring(seq), "\uD800\uDC82か\uD800\uDC33\uD800\uDC34");
    seq2.next();
    EQUAL(seq2.substring(seq), "か\uD800\uDC33\uD800\uDC34");
    seq2.next();
    EQUAL(seq2.substring(seq), "\uD800\uDC33\uD800\uDC34");
    seq2.next();
    EQUAL(seq2.substring(seq), "\uD800\uDC34");
    seq2.next();
    EQUAL(seq2.substring(seq), "");
    seq2.next();
    EQUAL(seq2.substring(seq), "");
  }

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

    StringSequence seq = new StringSequence("あいうえお");
    try {
      seq.substring((StringSequence) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
  }

  public void substring_seq_3()
  {
    MSG("引数のStringSequenceが自身よりも前のインデックスを指している場合。");

    StringSequence seq = new StringSequence("あいうえお");
    StringSequence seq2 = seq.copy();
    EQUAL(seq.substring(seq2), "");

    seq.next();
    try {
      seq.substring(seq2);
      NG();
    } catch (IndexOutOfBoundsException e) {
      OK(e);
    }

    seq = new StringSequence("a\uD800\uDC82か\uD800\uDC33\uD800\uDC34");
    seq2 = seq.copy();
    EQUAL(seq.substring(seq2), "");

    seq.next();
    try {
      seq.substring(seq2);
      NG();
    } catch (IndexOutOfBoundsException e) {
      OK(e);
    }
  }

  public void followingString()
  {
    MSG("現在のインデックスの次から開始する部分文字列を取得。");

    StringSequence seq = new StringSequence("", -1);
    EQUAL(seq.followingString(), "");
    seq.next();
    EQUAL(seq.followingString(), "");
    seq.next();
    EQUAL(seq.followingString(), "");

    seq = new StringSequence("abc", -1);
    EQUAL(seq.followingString(), "abc");
    seq.next();
    EQUAL(seq.followingString(), "bc");
    seq.next();
    EQUAL(seq.followingString(), "c");
    seq.next();
    EQUAL(seq.followingString(), "");
    seq.next();
    EQUAL(seq.followingString(), "");
    seq.next();
    EQUAL(seq.followingString(), "");

    seq.previous();
    EQUAL(seq.followingString(), "");
    seq.previous();
    EQUAL(seq.followingString(), "c");
    seq.previous();
    EQUAL(seq.followingString(), "bc");
    seq.previous();
    EQUAL(seq.followingString(), "abc");
    seq.previous();
    EQUAL(seq.followingString(), "abc");

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    EQUAL(seq.followingString(), "\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    EQUAL(seq.index(), -1);
    seq.next();
    EQUAL(seq.followingString(), "\uD800\uDC33\uD800\uDC34");
    EQUAL(seq.index(), 0);
    seq.next();
    EQUAL(seq.followingString(), "\uD800\uDC34");
    EQUAL(seq.index(), 1);
    seq.next();
    EQUAL(seq.followingString(), "");
    EQUAL(seq.index(), 2);
    seq.next();
    EQUAL(seq.followingString(), "");
    EQUAL(seq.index(), 3);

    seq.previous();
    EQUAL(seq.index(), 2);
    EQUAL(seq.followingString(), "");
    seq.previous();
    EQUAL(seq.index(), 1);
    EQUAL(seq.followingString(), "\uD800\uDC34");
    seq.previous();
    EQUAL(seq.index(), 0);
    EQUAL(seq.followingString(), "\uD800\uDC33\uD800\uDC34");
    seq.previous();
    EQUAL(seq.index(), -1);
    EQUAL(seq.followingString(), "\uD800\uDC32\uD800\uDC33\uD800\uDC34");
    seq.previous();
    EQUAL(seq.index(), -1);
    EQUAL(seq.followingString(), "\uD800\uDC32\uD800\uDC33\uD800\uDC34");
  }

  public void followingString_1()
  {
    MSG("文字列が空文字列の場合。");

    StringSequence seq = new StringSequence("");
    EQUAL(seq.followingString(), "");
  }

  public void followingString_seq()
  {
    MSG("引数のStringSequenceまでの部分文字列を取得。");

    StringSequence seq = new StringSequence("", -1);
    StringSequence seq2 = seq.copy();
    EQUAL(seq2.followingString(seq), "");
    seq.next();
    EQUAL(seq2.followingString(seq), "");
    seq.next();
    EQUAL(seq2.followingString(seq), "");

    seq = new StringSequence("あいうえお", -1);
    seq2 = seq.copy();
    EQUAL(seq2.followingString(seq), "");
    seq.next();
    EQUAL(seq2.followingString(seq), "");
    seq.next();
    EQUAL(seq2.followingString(seq), "あ");
    seq.next();
    EQUAL(seq2.followingString(seq), "あい");
    seq.next();
    EQUAL(seq2.followingString(seq), "あいう");
    seq.next();
    EQUAL(seq2.followingString(seq), "あいうえ");
    seq.next();
    EQUAL(seq2.followingString(seq), "あいうえお");
    seq.next();
    EQUAL(seq2.followingString(seq), "あいうえお");

    seq2.next();
    EQUAL(seq2.followingString(seq), "いうえお");
    seq2.next();
    EQUAL(seq2.followingString(seq), "うえお");
    seq2.next();
    EQUAL(seq2.followingString(seq), "えお");
    seq2.next();
    EQUAL(seq2.followingString(seq), "お");
    seq2.next();
    EQUAL(seq2.followingString(seq), "");
    seq2.next();
    EQUAL(seq2.followingString(seq), "");

    seq = new StringSequence("\uD800\uDC82か\uD800\uDC33\uD800\uDC34", -1);
    seq2 = seq.copy();
    EQUAL(seq2.followingString(seq), "");
    seq.next();
    EQUAL(seq2.followingString(seq), "");
    seq.next();
    EQUAL(seq2.followingString(seq), "\uD800\uDC82");
    seq.next();
    EQUAL(seq2.followingString(seq), "\uD800\uDC82か");
    seq.next();
    EQUAL(seq2.followingString(seq), "\uD800\uDC82か\uD800\uDC33");
    seq.next();
    EQUAL(seq2.followingString(seq), "\uD800\uDC82か\uD800\uDC33\uD800\uDC34");
    seq.next();
    EQUAL(seq2.followingString(seq), "\uD800\uDC82か\uD800\uDC33\uD800\uDC34");
    seq.next();
    EQUAL(seq2.followingString(seq), "\uD800\uDC82か\uD800\uDC33\uD800\uDC34");

    seq2.next();
    EQUAL(seq2.followingString(seq), "か\uD800\uDC33\uD800\uDC34");
    seq2.next();
    EQUAL(seq2.followingString(seq), "\uD800\uDC33\uD800\uDC34");
    seq2.next();
    EQUAL(seq2.followingString(seq), "\uD800\uDC34");
    seq2.next();
    EQUAL(seq2.followingString(seq), "");
    seq2.next();
    EQUAL(seq2.followingString(seq), "");
  }

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

    StringSequence seq = new StringSequence("あいうえお");
    try {
      seq.followingString((StringSequence) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
  }

  public void followingString_seq_2()
  {
    MSG("引数のStringSequenceが自身よりも前のインデックスを指している場合。");

    StringSequence seq = new StringSequence("あいうえお");
    StringSequence seq2 = seq.copy();
    EQUAL(seq.followingString(seq2), "");

    seq.next();
    try {
      seq.followingString(seq2);
      NG();
    } catch (IndexOutOfBoundsException e) {
      OK(e);
    }

    seq = new StringSequence("a\uD800\uDC82か\uD800\uDC33\uD800\uDC34");
    seq2 = seq.copy();
    EQUAL(seq.followingString(seq2), "");

    seq.next();
    try {
      seq.followingString(seq2);
      NG();
    } catch (IndexOutOfBoundsException e) {
      OK(e);
    }
  }

  public void restLength()
  {
    MSG("部分文字列の長さを取得。");

    StringSequence seq = new StringSequence("");
    EQUAL(seq.restLength(), 0);

    seq = new StringSequence("あいうえお");
    EQUAL(seq.restLength(), 5);
    seq.next();
    EQUAL(seq.restLength(), 4);
    seq.next();
    EQUAL(seq.restLength(), 3);
    seq.next();
    EQUAL(seq.restLength(), 2);
    seq.next();
    EQUAL(seq.restLength(), 1);
    seq.next();
    EQUAL(seq.restLength(), 0);

    seq = new StringSequence("\uD800\uDC33あ\uD800\uDC34a\uD800\uDC35");
    EQUAL(seq.restLength(), 5);
    seq.next();
    EQUAL(seq.restLength(), 4);
    seq.next();
    EQUAL(seq.restLength(), 3);
    seq.next();
    EQUAL(seq.restLength(), 2);
    seq.next();
    EQUAL(seq.restLength(), 1);
    seq.next();
    EQUAL(seq.restLength(), 0);
  }

  public void indexOf()
  {
    MSG("部分文字列から探索文字列のインデックスを取得。");

    StringSequence seq = new StringSequence("");
    EQUAL(seq.indexOf(""), 0);

    seq = new StringSequence("あいうえお", -1);
    EQUAL(seq.indexOf(""), 0);
    EQUAL(seq.indexOf("あ"), 0);
    EQUAL(seq.indexOf("い"), 1);
    EQUAL(seq.indexOf("う"), 2);
    EQUAL(seq.indexOf("え"), 3);
    EQUAL(seq.indexOf("お"), 4);
    seq.next();
    EQUAL(seq.indexOf(""), 0);
    EQUAL(seq.indexOf("あ"), 0);
    EQUAL(seq.indexOf("い"), 1);
    EQUAL(seq.indexOf("う"), 2);
    EQUAL(seq.indexOf("え"), 3);
    EQUAL(seq.indexOf("お"), 4);
    seq.next();
    EQUAL(seq.indexOf(""), 1);
    EQUAL(seq.indexOf("い"), 1);
    EQUAL(seq.indexOf("う"), 2);
    EQUAL(seq.indexOf("え"), 3);
    EQUAL(seq.indexOf("お"), 4);
    seq.next();
    EQUAL(seq.indexOf(""), 2);
    EQUAL(seq.indexOf("う"), 2);
    EQUAL(seq.indexOf("え"), 3);
    EQUAL(seq.indexOf("お"), 4);
    seq.next();
    EQUAL(seq.indexOf(""), 3);
    EQUAL(seq.indexOf("え"), 3);
    EQUAL(seq.indexOf("お"), 4);
    seq.next();
    EQUAL(seq.indexOf(""), 4);
    EQUAL(seq.indexOf("お"), 4);

    seq = new StringSequence("\uD800\uDC33あ\uD800\uDC34a\uD800\uDC35", -1);
    EQUAL(seq.indexOf(""), 0);
    EQUAL(seq.indexOf("\uD800\uDC33"), 0);
    EQUAL(seq.indexOf("あ"), 1);
    EQUAL(seq.indexOf("\uD800\uDC34"), 2);
    EQUAL(seq.indexOf("a"), 3);
    EQUAL(seq.indexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.indexOf(""), 0);
    EQUAL(seq.indexOf("\uD800\uDC33"), 0);
    EQUAL(seq.indexOf("あ"), 1);
    EQUAL(seq.indexOf("\uD800\uDC34"), 2);
    EQUAL(seq.indexOf("a"), 3);
    EQUAL(seq.indexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.indexOf(""), 1);
    EQUAL(seq.indexOf("あ"), 1);
    EQUAL(seq.indexOf("\uD800\uDC34"), 2);
    EQUAL(seq.indexOf("a"), 3);
    EQUAL(seq.indexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.indexOf(""), 2);
    EQUAL(seq.indexOf("\uD800\uDC34"), 2);
    EQUAL(seq.indexOf("a"), 3);
    EQUAL(seq.indexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.indexOf(""), 3);
    EQUAL(seq.indexOf("a"), 3);
    EQUAL(seq.indexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.indexOf(""), 4);
    EQUAL(seq.indexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.indexOf(""), 5);
    TRUE(seq.indexOf("\uD800\uDC35") < 0);
  }

  public void indexOf_1()
  {
    MSG("探索文字列が存在しない場合。");

    StringSequence seq = new StringSequence("");
    TRUE(seq.indexOf("a") < 0);

    seq = new StringSequence("あいうえお");
    TRUE(seq.indexOf("a") < 0);
    seq.next();
    TRUE(seq.indexOf("a") < 0);
    seq.next();
    TRUE(seq.indexOf("a") < 0);
    seq.next();
    TRUE(seq.indexOf("a") < 0);
    seq.next();
    TRUE(seq.indexOf("a") < 0);
    seq.next();

    seq = new StringSequence("\uD800\uDC33あ\uD800\uDC34a\uD800\uDC35");
    TRUE(seq.indexOf("abcdefgh") < 0);
    seq.next();
    TRUE(seq.indexOf("abcdefgh") < 0);
    seq.next();
    TRUE(seq.indexOf("abcdefgh") < 0);
    seq.next();
    TRUE(seq.indexOf("abcdefgh") < 0);
    seq.next();
    TRUE(seq.indexOf("abcdefgh") < 0);
    seq.next();
  }

  public void indexOf_2()
  {
    MSG("引数がヌルの場合。");
    StringSequence seq = new StringSequence("あいうえお");
    try {
      seq.indexOf((String) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
  }

  public void lastIndexOf()
  {
    MSG("部分文字列から探索文字列が最後に現れるインデックスを取得。");
    StringSequence seq = new StringSequence("");
    EQUAL(seq.lastIndexOf(""), 0);

    seq = new StringSequence("あいうえお", -1);
    EQUAL(seq.index(), -1);
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("あ"), 0);
    EQUAL(seq.lastIndexOf("い"), 1);
    EQUAL(seq.lastIndexOf("う"), 2);
    EQUAL(seq.lastIndexOf("え"), 3);
    EQUAL(seq.lastIndexOf("お"), 4);
    seq.next();
    EQUAL(seq.index(), 0);
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("あ"), 0);
    EQUAL(seq.lastIndexOf("い"), 1);
    EQUAL(seq.lastIndexOf("う"), 2);
    EQUAL(seq.lastIndexOf("え"), 3);
    EQUAL(seq.lastIndexOf("お"), 4);
    seq.next();
    EQUAL(seq.index(), 1);
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("い"), 1);
    EQUAL(seq.lastIndexOf("う"), 2);
    EQUAL(seq.lastIndexOf("え"), 3);
    EQUAL(seq.lastIndexOf("お"), 4);
    seq.next();
    EQUAL(seq.index(), 2);
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("う"), 2);
    EQUAL(seq.lastIndexOf("え"), 3);
    EQUAL(seq.lastIndexOf("お"), 4);
    seq.next();
    EQUAL(seq.index(), 3);
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("え"), 3);
    EQUAL(seq.lastIndexOf("お"), 4);
    seq.next();
    EQUAL(seq.index(), 4);
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("お"), 4);
    seq.next();
    EQUAL(seq.index(), 5);
    EQUAL(seq.lastIndexOf(""), 5);

    seq = new StringSequence("\uD800\uDC33あ\uD800\uDC34a\uD800\uDC35", -1);
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("\uD800\uDC33"), 0);
    EQUAL(seq.lastIndexOf("あ"), 1);
    EQUAL(seq.lastIndexOf("\uD800\uDC34"), 2);
    EQUAL(seq.lastIndexOf("a"), 3);
    EQUAL(seq.lastIndexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("\uD800\uDC33"), 0);
    EQUAL(seq.lastIndexOf("あ"), 1);
    EQUAL(seq.lastIndexOf("\uD800\uDC34"), 2);
    EQUAL(seq.lastIndexOf("a"), 3);
    EQUAL(seq.lastIndexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("あ"), 1);
    EQUAL(seq.lastIndexOf("\uD800\uDC34"), 2);
    EQUAL(seq.lastIndexOf("a"), 3);
    EQUAL(seq.lastIndexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("\uD800\uDC34"), 2);
    EQUAL(seq.lastIndexOf("a"), 3);
    EQUAL(seq.lastIndexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("a"), 3);
    EQUAL(seq.lastIndexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.lastIndexOf(""), 5);
    EQUAL(seq.lastIndexOf("\uD800\uDC35"), 4);
    seq.next();
    EQUAL(seq.lastIndexOf(""), 5);
    TRUE(seq.lastIndexOf("\uD800\uDC35") < 0);
  }

  public void lastIndexOf_1()
  {
    MSG("探索文字列が存在しない場合。");

    StringSequence seq = new StringSequence("", -1);
    TRUE(seq.lastIndexOf("a") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("a") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("a") < 0);

    seq = new StringSequence("あいうえお", -1);
    TRUE(seq.lastIndexOf("a") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("a") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("a") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("a") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("a") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("a") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("a") < 0);

    seq = new StringSequence("\uD800\uDC33あ\uD800\uDC34a\uD800\uDC35", -1);
    TRUE(seq.lastIndexOf("abcdefgh") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("abcdefgh") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("abcdefgh") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("abcdefgh") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("abcdefgh") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("abcdefgh") < 0);
    seq.next();
    TRUE(seq.lastIndexOf("abcdefgh") < 0);
  }

  public void lastIndexOf_2()
  {
    MSG("引数がヌルの場合。");
    StringSequence seq = new StringSequence("あいうえお");
    try {
      seq.lastIndexOf((String) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
  }

  public void startsWith()
  {
    MSG("プリフィックスが一致するか判定。");

    StringSequence seq = new StringSequence("");
    TRUE(seq.startsWith(""));

    seq = new StringSequence("あいうえお", -1);
    TRUE(seq.startsWith(""));
    TRUE(seq.startsWith("あ"));
    TRUE(seq.startsWith("あい"));
    TRUE(seq.startsWith("あいう"));
    TRUE(seq.startsWith("あいうえ"));
    TRUE(seq.startsWith("あいうえお"));
    seq.next();
    TRUE(seq.startsWith(""));
    TRUE(seq.startsWith("あ"));
    TRUE(seq.startsWith("あい"));
    TRUE(seq.startsWith("あいう"));
    TRUE(seq.startsWith("あいうえ"));
    TRUE(seq.startsWith("あいうえお"));
    seq.next();
    TRUE(seq.startsWith(""));
    TRUE(seq.startsWith("い"));
    TRUE(seq.startsWith("いう"));
    TRUE(seq.startsWith("いうえ"));
    TRUE(seq.startsWith("いうえお"));
    FALSE(seq.startsWith("あいうえお"));
    seq.next();
    TRUE(seq.startsWith(""));
    TRUE(seq.startsWith("う"));
    TRUE(seq.startsWith("うえ"));
    TRUE(seq.startsWith("うえお"));
    FALSE(seq.startsWith("いうえお"));
    FALSE(seq.startsWith("あいうえお"));
    seq.next();
    TRUE(seq.startsWith(""));
    TRUE(seq.startsWith("え"));
    TRUE(seq.startsWith("えお"));
    FALSE(seq.startsWith("うえお"));
    FALSE(seq.startsWith("いうえお"));
    FALSE(seq.startsWith("あいうえお"));
    seq.next();
    TRUE(seq.startsWith(""));
    TRUE(seq.startsWith("お"));
    FALSE(seq.startsWith("えお"));
    FALSE(seq.startsWith("うえお"));
    FALSE(seq.startsWith("いうえお"));
    FALSE(seq.startsWith("あいうえお"));
    seq.next();
    TRUE(seq.startsWith(""));
    FALSE(seq.startsWith("お"));
    FALSE(seq.startsWith("えお"));
    FALSE(seq.startsWith("うえお"));
    FALSE(seq.startsWith("いうえお"));
    FALSE(seq.startsWith("あいうえお"));

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    TRUE(seq.startsWith(""));
    TRUE(seq.startsWith("\uD800\uDC32"));
    TRUE(seq.startsWith("\uD800\uDC32\uD800\uDC33"));
    TRUE(seq.startsWith("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    seq.next();
    TRUE(seq.startsWith(""));
    TRUE(seq.startsWith("\uD800\uDC32"));
    TRUE(seq.startsWith("\uD800\uDC32\uD800\uDC33"));
    TRUE(seq.startsWith("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    seq.next();
    TRUE(seq.startsWith(""));
    TRUE(seq.startsWith("\uD800\uDC33"));
    TRUE(seq.startsWith("\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.startsWith("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    seq.next();
    TRUE(seq.startsWith(""));
    TRUE(seq.startsWith("\uD800\uDC34"));
    FALSE(seq.startsWith("\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.startsWith("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    seq.next();
    TRUE(seq.startsWith(""));
    FALSE(seq.startsWith("\uD800\uDC34"));
    FALSE(seq.startsWith("\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.startsWith("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
  }

  public void startsWith_1()
  {
    MSG("プリフィックスが一致しない場合。");

    StringSequence seq = new StringSequence("");
    FALSE(seq.startsWith("a"));

    seq = new StringSequence("あいうえお", -1);
    FALSE(seq.startsWith("お"));
    seq.next();
    FALSE(seq.startsWith("お"));
    seq.next();
    FALSE(seq.startsWith("お"));
    seq.next();
    FALSE(seq.startsWith("お"));
    seq.next();
    FALSE(seq.startsWith("お"));
    seq.next();
    FALSE(seq.startsWith("い"));
    seq.next();

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    FALSE(seq.startsWith("abcdefgh"));
    seq.next();
    FALSE(seq.startsWith("abcdefgh"));
    seq.next();
    FALSE(seq.startsWith("abcdefgh"));
    seq.next();
    FALSE(seq.startsWith("abcdefgh"));
    seq.next();
    FALSE(seq.startsWith("abcdefgh"));
  }

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

    StringSequence seq = new StringSequence("abc");
    try {
      seq.startsWith((String) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
  }

  public void endsWith()
  {
    MSG("サフィックスが一致するか判定。");

    StringSequence seq = new StringSequence("");
    TRUE(seq.endsWith(""));

    seq = new StringSequence("あいうえお", -1);
    TRUE(seq.endsWith("あいうえお"));
    TRUE(seq.endsWith("いうえお"));
    TRUE(seq.endsWith("うえお"));
    TRUE(seq.endsWith("えお"));
    TRUE(seq.endsWith("お"));
    TRUE(seq.endsWith(""));

    seq.next();
    TRUE(seq.endsWith("あいうえお"));
    TRUE(seq.endsWith("いうえお"));
    TRUE(seq.endsWith("うえお"));
    TRUE(seq.endsWith("えお"));
    TRUE(seq.endsWith("お"));
    TRUE(seq.endsWith(""));

    seq.next();
    FALSE(seq.endsWith("あいうえお"));
    TRUE(seq.endsWith("いうえお"));
    TRUE(seq.endsWith("うえお"));
    TRUE(seq.endsWith("えお"));
    TRUE(seq.endsWith("お"));
    TRUE(seq.endsWith(""));

    seq.next();
    FALSE(seq.endsWith("あいうえお"));
    FALSE(seq.endsWith("いうえお"));
    TRUE(seq.endsWith("うえお"));
    TRUE(seq.endsWith("えお"));
    TRUE(seq.endsWith("お"));
    TRUE(seq.endsWith(""));

    seq.next();
    FALSE(seq.endsWith("あいうえお"));
    FALSE(seq.endsWith("いうえお"));
    FALSE(seq.endsWith("うえお"));
    TRUE(seq.endsWith("えお"));
    TRUE(seq.endsWith("お"));
    TRUE(seq.endsWith(""));

    seq.next();
    FALSE(seq.endsWith("あいうえお"));
    FALSE(seq.endsWith("いうえお"));
    FALSE(seq.endsWith("うえお"));
    FALSE(seq.endsWith("えお"));
    TRUE(seq.endsWith("お"));
    TRUE(seq.endsWith(""));

    seq.next();
    FALSE(seq.endsWith("あいうえお"));
    FALSE(seq.endsWith("いうえお"));
    FALSE(seq.endsWith("うえお"));
    FALSE(seq.endsWith("えお"));
    FALSE(seq.endsWith("お"));
    TRUE(seq.endsWith(""));

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    TRUE(seq.endsWith("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    TRUE(seq.endsWith("\uD800\uDC33\uD800\uDC34"));
    TRUE(seq.endsWith("\uD800\uDC34"));
    TRUE(seq.endsWith(""));
    
    seq.next();
    TRUE(seq.endsWith("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    TRUE(seq.endsWith("\uD800\uDC33\uD800\uDC34"));
    TRUE(seq.endsWith("\uD800\uDC34"));
    TRUE(seq.endsWith(""));
    
    seq.next();
    FALSE(seq.endsWith("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    TRUE(seq.endsWith("\uD800\uDC33\uD800\uDC34"));
    TRUE(seq.endsWith("\uD800\uDC34"));
    TRUE(seq.endsWith(""));
    
    seq.next();
    FALSE(seq.endsWith("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.endsWith("\uD800\uDC33\uD800\uDC34"));
    TRUE(seq.endsWith("\uD800\uDC34"));
    TRUE(seq.endsWith(""));

    seq.next();
    FALSE(seq.endsWith("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.endsWith("\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.endsWith("\uD800\uDC34"));
    TRUE(seq.endsWith(""));
  }

  public void endsWith_1()
  {
    MSG("サフィックスが一致しない場合。");

    StringSequence seq = new StringSequence("");
    FALSE(seq.endsWith("a"));

    seq = new StringSequence("あいうえお", -1);
    FALSE(seq.endsWith("a"));
    seq.next();
    FALSE(seq.endsWith("a"));
    seq.next();
    FALSE(seq.endsWith("a"));
    seq.next();
    FALSE(seq.endsWith("a"));
    seq.next();
    FALSE(seq.endsWith("a"));
    seq.next();
    FALSE(seq.endsWith("a"));
    seq.next();
    FALSE(seq.endsWith("a"));

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    FALSE(seq.endsWith("\uD800\uDC44"));
    seq.next();
    FALSE(seq.endsWith("\uD800\uDC44"));
    seq.next();
    FALSE(seq.endsWith("\uD800\uDC44"));
    seq.next();
    FALSE(seq.endsWith("\uD800\uDC44"));
    seq.next();
    FALSE(seq.endsWith("\uD800\uDC44"));
  }

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

    StringSequence seq = new StringSequence("あいうえお");
    try {
      seq.endsWith((String) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
  }

  public void contains()
  {
    MSG("探索文字列が含まれているか確認。");

    StringSequence seq = new StringSequence("");
    TRUE(seq.contains(""));

    seq = new StringSequence("あいうえお", -1);
    EQUAL(seq.index(), -1);
    TRUE(seq.contains("あいうえお"));
    TRUE(seq.contains("あい"));
    TRUE(seq.contains("うえ"));
    TRUE(seq.contains("あ"));
    TRUE(seq.contains("い"));
    TRUE(seq.contains("う"));
    TRUE(seq.contains("え"));
    TRUE(seq.contains("お"));

    seq.next();
    EQUAL(seq.index(), 0);
    TRUE(seq.contains("あいうえお"));
    TRUE(seq.contains("あい"));
    TRUE(seq.contains("うえ"));
    TRUE(seq.contains("あ"));
    TRUE(seq.contains("い"));
    TRUE(seq.contains("う"));
    TRUE(seq.contains("え"));
    TRUE(seq.contains("お"));

    seq.next();
    EQUAL(seq.index(), 1);
    FALSE(seq.contains("あいうえお"));
    FALSE(seq.contains("あい"));
    TRUE(seq.contains("うえ"));
    FALSE(seq.contains("あ"));
    TRUE(seq.contains("い"));
    TRUE(seq.contains("う"));
    TRUE(seq.contains("え"));
    TRUE(seq.contains("お"));

    seq.next();
    EQUAL(seq.index(), 2);
    FALSE(seq.contains("あいうえお"));
    FALSE(seq.contains("あい"));
    TRUE(seq.contains("うえ"));
    FALSE(seq.contains("あ"));
    FALSE(seq.contains("い"));
    TRUE(seq.contains("う"));
    TRUE(seq.contains("え"));
    TRUE(seq.contains("お"));

    seq.next();
    EQUAL(seq.index(), 3);
    FALSE(seq.contains("あいうえお"));
    FALSE(seq.contains("あい"));
    FALSE(seq.contains("うえ"));
    FALSE(seq.contains("あ"));
    FALSE(seq.contains("い"));
    FALSE(seq.contains("う"));
    TRUE(seq.contains("え"));
    TRUE(seq.contains("お"));

    seq.next();
    EQUAL(seq.index(), 4);
    FALSE(seq.contains("あいうえお"));
    FALSE(seq.contains("あい"));
    FALSE(seq.contains("うえ"));
    FALSE(seq.contains("あ"));
    FALSE(seq.contains("い"));
    FALSE(seq.contains("う"));
    FALSE(seq.contains("え"));
    TRUE(seq.contains("お"));

    seq.next();
    EQUAL(seq.index(), 5);
    FALSE(seq.contains("あいうえお"));
    FALSE(seq.contains("あい"));
    FALSE(seq.contains("うえ"));
    FALSE(seq.contains("あ"));
    FALSE(seq.contains("い"));
    FALSE(seq.contains("う"));
    FALSE(seq.contains("え"));
    FALSE(seq.contains("お"));

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    TRUE(seq.contains("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    TRUE(seq.contains("\uD800\uDC32\uD800\uDC33"));
    TRUE(seq.contains("\uD800\uDC33\uD800\uDC34"));
    TRUE(seq.contains("\uD800\uDC32"));
    TRUE(seq.contains("\uD800\uDC33"));
    TRUE(seq.contains("\uD800\uDC34"));

    seq.next();
    TRUE(seq.contains("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    TRUE(seq.contains("\uD800\uDC32\uD800\uDC33"));
    TRUE(seq.contains("\uD800\uDC33\uD800\uDC34"));
    TRUE(seq.contains("\uD800\uDC32"));
    TRUE(seq.contains("\uD800\uDC33"));
    TRUE(seq.contains("\uD800\uDC34"));

    seq.next();
    FALSE(seq.contains("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.contains("\uD800\uDC32\uD800\uDC33"));
    TRUE(seq.contains("\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.contains("\uD800\uDC32"));
    TRUE(seq.contains("\uD800\uDC33"));
    TRUE(seq.contains("\uD800\uDC34"));

    seq.next();
    FALSE(seq.contains("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.contains("\uD800\uDC32\uD800\uDC33"));
    FALSE(seq.contains("\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.contains("\uD800\uDC32"));
    FALSE(seq.contains("\uD800\uDC33"));
    TRUE(seq.contains("\uD800\uDC34"));

    seq.next();
    FALSE(seq.contains("\uD800\uDC32\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.contains("\uD800\uDC32\uD800\uDC33"));
    FALSE(seq.contains("\uD800\uDC33\uD800\uDC34"));
    FALSE(seq.contains("\uD800\uDC32"));
    FALSE(seq.contains("\uD800\uDC33"));
    FALSE(seq.contains("\uD800\uDC34"));
  }

  public void contains_1()
  {
    MSG("探索文字列が含まれていない場合。");

    StringSequence seq = new StringSequence("", -1);
    FALSE(seq.contains("a"));
    seq.next();
    FALSE(seq.contains("a"));

    seq = new StringSequence("あいうえお", -1);
    FALSE(seq.contains("a"));
    seq.next();
    FALSE(seq.contains("a"));
    seq.next();
    FALSE(seq.contains("a"));
    seq.next();
    FALSE(seq.contains("a"));
    seq.next();
    FALSE(seq.contains("a"));
    seq.next();
    FALSE(seq.contains("a"));
    seq.next();
    FALSE(seq.contains("a"));

    seq = new StringSequence("\uD800\uDC32\uD800\uDC33\uD800\uDC34", -1);
    FALSE(seq.contains("\uD800\uDC44"));
    FALSE(seq.contains("\uD800\uDC44"));
    seq.next();
    FALSE(seq.contains("\uD800\uDC44"));
    seq.next();
    FALSE(seq.contains("\uD800\uDC44"));
    seq.next();
    FALSE(seq.contains("\uD800\uDC44"));
    seq.next();
    FALSE(seq.contains("\uD800\uDC44"));
  }

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

    StringSequence seq = new StringSequence("あいうえお");
    try {
      seq.contains((String) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    }
  }

  public void nextUntil()
  {
    MSG("文字列が見つかるまで次に進める。");

    StringSequence seq = new StringSequence("abc");
    EQUAL(seq.index(), 0);
    EQUAL(seq.nextUntil("a").index(), 0);

    seq = new StringSequence("abc");
    EQUAL(seq.index(), 0);
    EQUAL(seq.nextUntil("b").index(), 1);

    seq = new StringSequence("abc");
    EQUAL(seq.index(), 0);
    EQUAL(seq.nextUntil("c").index(), 2);

    seq = new StringSequence("abc");
    EQUAL(seq.index(), 0);
    EQUAL(seq.nextUntil("").index(), 0);

    seq = new StringSequence("");
    EQUAL(seq.index(), 0);
    EQUAL(seq.nextUntil("").index(), 0);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC34");
    EQUAL(seq.index(), 0);
    EQUAL(seq.nextUntil("\uD800\uDC32").index(), 0);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC34");
    EQUAL(seq.index(), 0);
    EQUAL(seq.nextUntil("\uD800\uDC34").index(), 1);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC34");
    EQUAL(seq.index(), 0);
    EQUAL(seq.nextUntil("").index(), 0);

    seq = new StringSequence("abc", -1);
    EQUAL(seq.index(), -1);
    EQUAL(seq.nextUntil("c").index(), 2);

    seq = new StringSequence("", -1);
    EQUAL(seq.index(), -1);
    EQUAL(seq.nextUntil("").index(), 0);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC34", -1);
    EQUAL(seq.index(), -1);
    EQUAL(seq.nextUntil("\uD800\uDC34").index(), 1);
  }

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

    StringSequence seq = new StringSequence("abc");
    try {
      seq.nextUntil(null);
    } catch (AssertionError e) {
      OK(e);
    }
  }

  public void nextUntil_2()
  {
    MSG("指定された文字列が見つからない場合。");

    StringSequence seq = new StringSequence("abc");
    EQUAL(seq.index(), 0);
    EQUAL(seq.nextUntil("d").index(), 3);

    seq = new StringSequence("\uD800\uDC32\uD800\uDC34");
    EQUAL(seq.index(), 0);
    EQUAL(seq.nextUntil("\uD800\uDC40").index(), 2);

    seq = new StringSequence("");
    EQUAL(seq.index(), 0);
    EQUAL(seq.nextUntil("x").index(), 0);
  }

  public void skipWhitespaces()
  {
    MSG("空白をスキップ。");

    StringSequence seq = new StringSequence("   abc");
    EQUAL(seq.index(), 0);
    seq.skipWhitespaces();
    EQUAL(seq.index(), 3);

    seq = new StringSequence("abc  def", 3);
    EQUAL(seq.index(), 3);
    seq.skipWhitespaces();
    EQUAL(seq.index(), 5);

    seq = new StringSequence("   ");
    EQUAL(seq.index(), 0);
    seq.skipWhitespaces();
    EQUAL(seq.index(), 3);
  }

  public void startsWithOneOf_Strings()
  {
    MSG("先頭が一致するかどうかを判定。");

    List<String> strL = new ArrayList<String>();
    strL.add("<HTML>");
    strL.add("<HEAD>");
    strL.add("<TITLE>");
    strL.add("</TITLE>");
    strL.add("</HEAD>");
    strL.add("<BODY>");
    strL.add("</BODY>");
    strL.add("</HTML>");

    String s = "<HTML><HEAD><TITLE>たいとる</TITLE></HEAD><BODY>本文。</BODY></HTML>";

    StringSequence seq = new StringSequence(s);
    EQUAL(seq.startsWithOneOf(strL), "<HTML>");
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), "<HEAD>");
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), "<TITLE>");
    EQUAL(seq.next().startsWithOneOf(strL), null);

    seq = new StringSequence(s, -1);
    EQUAL(seq.startsWithOneOf(strL), "<HTML>");
    EQUAL(seq.next().startsWithOneOf(strL), "<HTML>");
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), null);
    EQUAL(seq.next().startsWithOneOf(strL), "<HEAD>");
    EQUAL(seq.next().startsWithOneOf(strL), null);


    s = "<Html><head><tiTLE>たいとる</title></head><BODy>本文。</bODY></HtML>";
    StringSequence upperSeq = new StringSequence(s.toUpperCase());
    StringSequence bgn = new StringSequence(s);

    EQUAL(upperSeq.startsWithOneOf(strL), "<HTML>");
    EQUAL(bgn.substring(upperSeq), "");
    upperSeq.next(StringOperation.length("<HTML>"));
    bgn.next(StringOperation.length("<HTML>"));

    EQUAL(upperSeq.startsWithOneOf(strL), "<HEAD>");
    EQUAL(bgn.substring(upperSeq), "");
    upperSeq.next(StringOperation.length("<HEAD>"));
    bgn.next(StringOperation.length("<HEAD>"));

    EQUAL(upperSeq.startsWithOneOf(strL), "<TITLE>");
    EQUAL(bgn.substring(upperSeq), "");
    upperSeq.next(StringOperation.length("<TITLE>"));
    bgn.next(StringOperation.length("<TITLE>"));

    EQUAL(upperSeq.startsWithOneOf(strL), null);
    upperSeq.next();
    EQUAL(upperSeq.startsWithOneOf(strL), null);
    upperSeq.next();
    EQUAL(upperSeq.startsWithOneOf(strL), null);
    upperSeq.next();
    EQUAL(upperSeq.startsWithOneOf(strL), null);
    upperSeq.next();

    EQUAL(upperSeq.startsWithOneOf(strL), "</TITLE>");
    EQUAL(bgn.substring(upperSeq), "たいとる");
    upperSeq.next(StringOperation.length("</TITLE>"));
    bgn.next(StringOperation.length("</TITLE>"));

    EQUAL(upperSeq.startsWithOneOf(strL), "</HEAD>");
  }

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

    StringSequence seq = new StringSequence("abc");
    try {
      seq.startsWithOneOf((Collection<String>) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void startsWithOneOf_Strings_3()
  {
    MSG("文字列集合の中にヌルや空文字列が含まれていた場合。");

    List<String> strL = new ArrayList<String>();
    strL.add("<HTML>");
    strL.add("");
    strL.add("<TITLE>");
    strL.add("</TITLE>");
    strL.add("</HEAD>");
    strL.add("<BODY>");
    strL.add("</BODY>");
    strL.add("</HTML>");

    String s = "<HTML><HEAD><TITLE>たいとる</TITLE></HEAD><BODY>本文。</BODY></HTML>";

    StringSequence seq = new StringSequence(s);
    try {
      seq.startsWithOneOf(strL);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    strL = new ArrayList<String>();
    strL.add("<HTML>");
    strL.add("<HEAD>");
    strL.add("<TITLE>");
    strL.add(null);
    strL.add("</HEAD>");
    strL.add("<BODY>");
    strL.add("</BODY>");
    strL.add("</HTML>");
    seq = new StringSequence(s);
    try {
      seq.startsWithOneOf(strL);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void startsWithOneOf_StringSequence()
  {
    MSG("一致する文字列が存在する場合。");

    List<StringSequence> seqL = new ArrayList<StringSequence>();
    seqL.add(new StringSequence("<HTML>"));
    seqL.add(new StringSequence("<HEAD>"));
    seqL.add(new StringSequence("<TITLE>"));
    seqL.add(new StringSequence("</TITLE>"));
    seqL.add(new StringSequence("</HEAD>"));
    seqL.add(new StringSequence("<BODY>"));
    seqL.add(new StringSequence("</BODY>"));
    seqL.add(new StringSequence("</HTML>"));

    String s = "<HTML><HEAD><TITLE>たいとる</TITLE></HEAD><BODY>本文。</BODY></HTML>";

    StringSequence seq = new StringSequence(s);
    EQUAL(seq.startsWithOneOf(seqL).substring(), "<HTML>");
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL).substring(), "<HEAD>");
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL).substring(), "<TITLE>");
    EQUAL(seq.next().startsWithOneOf(seqL), null);

    seq = new StringSequence(s, -1);
    EQUAL(seq.startsWithOneOf(seqL).substring(), "<HTML>");
    EQUAL(seq.next().startsWithOneOf(seqL).substring(), "<HTML>");
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL), null);
    EQUAL(seq.next().startsWithOneOf(seqL).substring(), "<HEAD>");
    EQUAL(seq.next().startsWithOneOf(seqL), null);


    s = "<Html><head><tiTLE>たいとる</title></head><BODy>本文。</bODY></HtML>";
    StringSequence upperSeq = new StringSequence(s.toUpperCase());
    StringSequence bgn = new StringSequence(s);

    EQUAL(upperSeq.startsWithOneOf(seqL).substring(), "<HTML>");
    EQUAL(bgn.substring(upperSeq), "");
    upperSeq.next(StringOperation.length("<HTML>"));
    bgn.next(StringOperation.length("<HTML>"));

    EQUAL(upperSeq.startsWithOneOf(seqL).substring(), "<HEAD>");
    EQUAL(bgn.substring(upperSeq), "");
    upperSeq.next(StringOperation.length("<HEAD>"));
    bgn.next(StringOperation.length("<HEAD>"));

    EQUAL(upperSeq.startsWithOneOf(seqL).substring(), "<TITLE>");
    EQUAL(bgn.substring(upperSeq), "");
    upperSeq.next(StringOperation.length("<TITLE>"));
    bgn.next(StringOperation.length("<TITLE>"));

    EQUAL(upperSeq.startsWithOneOf(seqL), null);
    upperSeq.next();
    EQUAL(upperSeq.startsWithOneOf(seqL), null);
    upperSeq.next();
    EQUAL(upperSeq.startsWithOneOf(seqL), null);
    upperSeq.next();
    EQUAL(upperSeq.startsWithOneOf(seqL), null);
    upperSeq.next();

    EQUAL(upperSeq.startsWithOneOf(seqL).substring(), "</TITLE>");
    EQUAL(bgn.substring(upperSeq), "たいとる");
    upperSeq.next(StringOperation.length("</TITLE>"));
    bgn.next(StringOperation.length("</TITLE>"));

    EQUAL(upperSeq.startsWithOneOf(seqL).substring(), "</HEAD>");
  }

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

    StringSequence seq = new StringSequence("abc");
    try {
      seq.startsWithOneOf((Collection<StringSequence>) null);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void startsWithOneOf_StringSequence_3()
  {
    MSG("文字列集合の中にヌルや空文字列が含まれていた場合。");

    List<StringSequence> seqL = new ArrayList<StringSequence>();
    seqL.add(new StringSequence("<HTML>"));
    seqL.add(new StringSequence(""));
    seqL.add(new StringSequence("<TITLE>"));
    seqL.add(new StringSequence("</TITLE>"));
    seqL.add(new StringSequence("</HEAD>"));
    seqL.add(new StringSequence("<BODY>"));
    seqL.add(new StringSequence("</BODY>"));
    seqL.add(new StringSequence("</HTML>"));

    String s = "<HTML><HEAD><TITLE>たいとる</TITLE></HEAD><BODY>本文。</BODY></HTML>";

    StringSequence seq = new StringSequence(s);
    try {
      seq.startsWithOneOf(seqL);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    seqL = new ArrayList<StringSequence>();
    seqL.add(new StringSequence("<HTML>"));
    seqL.add(new StringSequence("<HEAD>"));
    seqL.add(new StringSequence("<TITLE>"));
    seqL.add(new StringSequence("</TITLE>").next(8));
    seqL.add(new StringSequence("</HEAD>"));
    seqL.add(new StringSequence("<BODY>"));
    seqL.add(new StringSequence("</BODY>"));
    seqL.add(new StringSequence("</HTML>"));
    seq = new StringSequence(s);
    try {
      seq.startsWithOneOf(seqL);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }

    seqL = new ArrayList<StringSequence>();
    seqL.add(new StringSequence("<HTML>"));
    seqL.add(new StringSequence("<HEAD>"));
    seqL.add(new StringSequence("<TITLE>"));
    seqL.add(null);
    seqL.add(new StringSequence("</HEAD>"));
    seqL.add(new StringSequence("<BODY>"));
    seqL.add(new StringSequence("</BODY>"));
    seqL.add(new StringSequence("</HTML>"));
    seq = new StringSequence(s);
    try {
      seq.startsWithOneOf(seqL);
      NG();
    } catch (AssertionError e) {
      OK(e);
    } catch (Exception e) {
      NG(e);
    }
  }

  public void _equals()
  {
    MSG("引数のオブジェクトと内容が等しいかどうかを確認。");

    StringSequence seq1 = new StringSequence("abc"); 
    StringSequence seq2 = new StringSequence("abc"); 
    StringSequence seq3 = new StringSequence("bc"); 
    StringSequence seq4 = new StringSequence("c"); 
    StringSequence seq5 = new StringSequence(""); 

    TRUE (seq1.equals(seq1));
    TRUE (seq1.equals(seq2));
    FALSE(seq1.equals(seq3));
    FALSE(seq1.equals(seq4));
    FALSE(seq1.equals(seq5));

    seq1.next();

    TRUE (seq1.equals(seq1));
    FALSE(seq1.equals(seq2));
    TRUE (seq1.equals(seq3));
    FALSE(seq1.equals(seq4));
    FALSE(seq1.equals(seq5));

    seq1.next();

    TRUE (seq1.equals(seq1));
    FALSE(seq1.equals(seq2));
    FALSE(seq1.equals(seq3));
    TRUE (seq1.equals(seq4));
    FALSE(seq1.equals(seq5));

    seq1.next();

    TRUE (seq1.equals(seq1));
    FALSE(seq1.equals(seq2));
    FALSE(seq1.equals(seq3));
    FALSE(seq1.equals(seq4));
    TRUE (seq1.equals(seq5));
  }

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

    StringSequence seq = new StringSequence("abc");
    FALSE(seq.equals(null));

    seq.next();
    FALSE(seq.equals(null));

    seq.next();
    FALSE(seq.equals(null));
  }

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

    StringSequence seq1 = new StringSequence("abc");
    StringSequence seq2 = new StringSequence("abc");

    EQUAL(seq1.hashCode(), seq2.hashCode());

    seq1.next();
    seq2.next();

    EQUAL(seq1.hashCode(), seq2.hashCode());

    seq1.next();
    seq2.next();

    EQUAL(seq1.hashCode(), seq2.hashCode());
  }
}
