@Test(expected = IndexOutOfBoundsException.class)
  public void searchNegativeStartOffsetTest() throws Exception {
    final ParserHandle hParser = new ParserHandle(4);
    try {
      final KeyOptions kopts = new KeyOptions();
      kopts.FixedString = false;
      kopts.CaseInsensitive = false;

      hParser.addKeyword("a+b", 0, kopts, "ASCII");

      final ProgramOptions popts = new ProgramOptions();
      popts.Determinize = true;

      final ProgramHandle hProg = hParser.createProgram(popts);
      try {
        final ContextOptions copts = new ContextOptions();

        final ContextHandle hCtx = hProg.createContext(copts);
        try {
          final byte[] buf = "aaabaacabbabcacbaccbbbcbccca".getBytes("ASCII");

          final List<SearchHit> hits = new ArrayList<SearchHit>();
          final HitCallback cb = new HitCollector(hits);

          hCtx.search(buf, 0, buf.length, -1, cb);
        } finally {
          hCtx.destroy();
        }
      } finally {
        hProg.destroy();
      }
    } finally {
      hParser.destroy();
    }
  }
  @Test
  public void resetContextTest() throws Exception {
    final ParserHandle hParser = new ParserHandle(4);
    try {
      final KeyOptions kopts = new KeyOptions();
      kopts.FixedString = false;
      kopts.CaseInsensitive = false;

      hParser.addKeyword("meh", 0, kopts, "ASCII");

      final ProgramOptions popts = new ProgramOptions();
      popts.Determinize = true;

      final ProgramHandle hProg = hParser.createProgram(popts);
      try {
        final ContextOptions copts = new ContextOptions();

        final ContextHandle hCtx = hProg.createContext(copts);
        try {
          hCtx.reset();
        } finally {
          hCtx.destroy();
        }
      } finally {
        hProg.destroy();
      }
    } finally {
      hParser.destroy();
    }
  }
  @Test(expected = NullPointerException.class)
  public void searchNullBufferTest() throws Exception {
    final ParserHandle hParser = new ParserHandle(4);
    try {
      final KeyOptions kopts = new KeyOptions();
      kopts.FixedString = false;
      kopts.CaseInsensitive = false;

      hParser.addKeyword("a+b", 0, kopts, "ASCII");

      final ProgramOptions popts = new ProgramOptions();
      popts.Determinize = true;

      final ProgramHandle hProg = hParser.createProgram(popts);
      try {
        final ContextOptions copts = new ContextOptions();

        final ContextHandle hCtx = hProg.createContext(copts);
        try {
          final List<SearchHit> hits = new ArrayList<SearchHit>();
          final HitCallback cb = new HitCollector(hits);

          hCtx.search(null, 0, 0, 0, cb);
        } finally {
          hCtx.destroy();
        }
      } finally {
        hProg.destroy();
      }
    } finally {
      hParser.destroy();
    }
  }
  @Test(expected = IllegalStateException.class)
  public void noStartsWithAfterDestroyContextTest() throws Exception {
    final ParserHandle hParser = new ParserHandle(4);
    try {
      final KeyOptions kopts = new KeyOptions();
      kopts.FixedString = false;
      kopts.CaseInsensitive = false;

      hParser.addKeyword("meh", 0, kopts, "ASCII");

      final ProgramOptions popts = new ProgramOptions();
      popts.Determinize = true;

      final ProgramHandle hProg = hParser.createProgram(popts);
      try {
        final ContextOptions copts = new ContextOptions();

        final ContextHandle hCtx = hProg.createContext(copts);
        hCtx.destroy();

        final byte[] buf = "a".getBytes("ASCII");
        final HitCallback cb = new DummyCallback();

        hCtx.startsWith(buf, 0, buf.length, 0, cb);
      } finally {
        hProg.destroy();
      }
    } finally {
      hParser.destroy();
    }
  }
  @Test(expected = NullPointerException.class)
  public void startsWithNullCallbackTest() throws Exception {
    final ParserHandle hParser = new ParserHandle(4);
    try {
      final KeyOptions kopts = new KeyOptions();
      kopts.FixedString = false;
      kopts.CaseInsensitive = false;

      hParser.addKeyword("x+", 0, kopts, "ASCII");

      final ProgramOptions popts = new ProgramOptions();
      popts.Determinize = true;

      final ProgramHandle hProg = hParser.createProgram(popts);
      try {
        final ContextOptions copts = new ContextOptions();

        final ContextHandle hCtx = hProg.createContext(copts);
        try {
          final byte[] buf = "xxxx".getBytes("ASCII");

          hCtx.startsWith(buf, 0, buf.length, 0, null);
        } finally {
          hCtx.destroy();
        }
      } finally {
        hProg.destroy();
      }
    } finally {
      hParser.destroy();
    }
  }
  @Test(expected = RuntimeException.class)
  public void searchBadCallbackTest() throws Exception {
    final ParserHandle hParser = new ParserHandle(4);
    try {
      final KeyOptions kopts = new KeyOptions();
      kopts.FixedString = false;
      kopts.CaseInsensitive = false;

      hParser.addKeyword("a+b", 0, kopts, "ASCII");

      final ProgramOptions popts = new ProgramOptions();
      popts.Determinize = true;

      final ProgramHandle hProg = hParser.createProgram(popts);
      try {
        final ContextOptions copts = new ContextOptions();

        final ContextHandle hCtx = hProg.createContext(copts);
        try {
          final byte[] buf = "aaabaacabbabcacbaccbbbcbccca".getBytes("ASCII");

          hCtx.search(buf, 0, buf.length, 0, new CallbackExploder());
        } finally {
          hCtx.destroy();
        }
      } finally {
        hProg.destroy();
      }
    } finally {
      hParser.destroy();
    }
  }
  @Test
  public void searchHitsTest() throws Exception {
    final ParserHandle hParser = new ParserHandle(4);
    try {
      final KeyOptions kopts = new KeyOptions();
      kopts.FixedString = false;
      kopts.CaseInsensitive = false;

      hParser.addKeyword("a+b", 0, kopts, "ASCII");

      final ProgramOptions popts = new ProgramOptions();
      popts.Determinize = true;

      final ProgramHandle hProg = hParser.createProgram(popts);
      try {
        final ContextOptions copts = new ContextOptions();

        final ContextHandle hCtx = hProg.createContext(copts);
        try {
          final byte[] buf = "aaabaacabbabcacbaccbbbcbccca".getBytes("ASCII");

          final List<SearchHit> hits = new ArrayList<SearchHit>();
          final HitCallback cb = new HitCollector(hits);

          final int ret = hCtx.search(buf, 0, buf.length, 0, cb);
          assertEquals(0, ret);

          hCtx.closeoutSearch(cb);

          assertEquals(3, hits.size());
          assertEquals(new SearchHit(0, 4, 0), hits.get(0));
          assertEquals(new SearchHit(7, 9, 0), hits.get(1));
          assertEquals(new SearchHit(10, 12, 0), hits.get(2));
        } finally {
          hCtx.destroy();
        }
      } finally {
        hProg.destroy();
      }
    } finally {
      hParser.destroy();
    }
  }
  @Test
  public void startsWithHitsTest() throws Exception {
    final ParserHandle hParser = new ParserHandle(4);
    try {
      final KeyOptions kopts = new KeyOptions();
      kopts.FixedString = false;
      kopts.CaseInsensitive = false;

      hParser.addKeyword("x+", 0, kopts, "ASCII");

      final ProgramOptions popts = new ProgramOptions();
      popts.Determinize = true;

      final ProgramHandle hProg = hParser.createProgram(popts);
      try {
        final ContextOptions copts = new ContextOptions();

        final ContextHandle hCtx = hProg.createContext(copts);
        try {
          final byte[] buf = "xxxx".getBytes("ASCII");

          final List<SearchHit> hits = new ArrayList<SearchHit>();
          final HitCallback cb = new HitCollector(hits);
          hCtx.startsWith(buf, 0, buf.length, 0, cb);

          assertEquals(1, hits.size());
          assertEquals(new SearchHit(0, 4, 0), hits.get(0));
        } finally {
          hCtx.destroy();
        }
      } finally {
        hProg.destroy();
      }
    } finally {
      hParser.destroy();
    }
  }