@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(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 = 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
  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 = 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 = 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 readWriteProgramGoodTest() {
    final byte[] exp = aProgram;

    final ProgramHandle hProg = ProgramHandle.read(exp, 0, exp.length);
    try {
      final int size = hProg.size();
      assertEquals(exp.length, size);

      final byte[] buf = new byte[size];
      hProg.write(buf, 0);

      assertArrayEquals(exp, buf);
    } finally {
      hProg.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 writeProgramGoodTest() 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 byte[] exp = {
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x01, 0x6D, 0x00, 0x00,
          0x0B, 0x00, 0x00, 0x00, 0x01, 0x65, 0x00, 0x00,
          0x01, 0x68, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
          0x07, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
          0x07, 0x00, 0x00, 0x00
        };

        final int size = hProg.size();
        assertEquals(exp.length, size);

        final byte[] buf = new byte[size];
        hProg.write(buf, 0);

        assertArrayEquals(exp, buf);
      } finally {
        hProg.destroy();
      }
    } finally {
      hParser.destroy();
    }
  }
  @Test(expected = IllegalStateException.class)
  public void noSizeAfterDestroyProgramTest() 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);
      hProg.destroy();

      hProg.size();
    } finally {
      hParser.destroy();
    }
  }
  @Test(expected = NullPointerException.class)
  public void createContextNullOptionsTest() 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 ContextHandle hCtx = hProg.createContext(null);
      } finally {
        hProg.destroy();
      }
    } finally {
      hParser.destroy();
    }
  }
  @Test
  public void createProgramGoodTest() 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 {
        assertNotNull(hProg);
      } 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();
    }
  }
  @Test(expected = IndexOutOfBoundsException.class)
  public void writeProgramOffsetTooLargeTest() 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 byte[] buf = new byte[hProg.size()];
        hProg.write(buf, 1);
      } finally {
        hProg.destroy();
      }
    } finally {
      hParser.destroy();
    }
  }
 @Test(expected = IndexOutOfBoundsException.class)
 public void readProgramOffsetTooLargeTest() {
   final byte[] exp = aProgram;
   final ProgramHandle hProg = ProgramHandle.read(exp, 1, exp.length);
 }
 @Test(expected = NullPointerException.class)
 public void readProgramNullBufferTest() {
   final ProgramHandle hProg = ProgramHandle.read(null, 0, 1);
 }