@Test
  public void testWholeIndelReadInIsolation() {
    final int firstLocus = 44367789;

    // create a test version of the Reads object
    ReadProperties readAttributes = createTestReadProperties();

    SAMRecord indelOnlyRead =
        ArtificialSAMUtils.createArtificialRead(header, "indelOnly", 0, firstLocus, 76);
    indelOnlyRead.setReadBases(Utils.dupBytes((byte) 'A', 76));
    indelOnlyRead.setBaseQualities(Utils.dupBytes((byte) '@', 76));
    indelOnlyRead.setCigarString("76I");

    List<SAMRecord> reads = Arrays.asList(indelOnlyRead);

    // create the iterator by state with the fake reads and fake records
    li = makeLTBS(reads, readAttributes);

    // Traditionally, reads that end with indels bleed into the pileup at the following locus.
    // Verify that the next pileup contains this read
    // and considers it to be an indel-containing read.
    Assert.assertTrue(
        li.hasNext(),
        "Should have found a whole-indel read in the normal base pileup without extended events enabled");
    AlignmentContext alignmentContext = li.next();
    Assert.assertEquals(
        alignmentContext.getLocation().getStart(),
        firstLocus,
        "Base pileup is at incorrect location.");
    ReadBackedPileup basePileup = alignmentContext.getBasePileup();
    Assert.assertEquals(basePileup.getReads().size(), 1, "Pileup is of incorrect size");
    Assert.assertSame(basePileup.getReads().get(0), indelOnlyRead, "Read in pileup is incorrect");
  }
  @Test(dataProvider = "LIBSTest")
  public void testLIBS(LIBSTest params) {
    final int locus = 44367788;

    SAMRecord read =
        ArtificialSAMUtils.createArtificialRead(header, "read", 0, locus, params.readLength);
    read.setReadBases(Utils.dupBytes((byte) 'A', params.readLength));
    read.setBaseQualities(Utils.dupBytes((byte) '@', params.readLength));
    read.setCigarString(params.cigar);

    // create the iterator by state with the fake reads and fake records
    li = makeLTBS(Arrays.asList(read), createTestReadProperties());
    final LIBS_position tester = new LIBS_position(read);

    while (li.hasNext()) {
      AlignmentContext alignmentContext = li.next();
      ReadBackedPileup p = alignmentContext.getBasePileup();
      Assert.assertTrue(p.getNumberOfElements() == 1);
      PileupElement pe = p.iterator().next();

      tester.stepForwardOnGenome();

      Assert.assertEquals(pe.isBeforeDeletedBase(), tester.isBeforeDeletedBase);
      Assert.assertEquals(pe.isBeforeDeletionStart(), tester.isBeforeDeletionStart);
      Assert.assertEquals(pe.isAfterDeletedBase(), tester.isAfterDeletedBase);
      Assert.assertEquals(pe.isAfterDeletionEnd(), tester.isAfterDeletionEnd);
      Assert.assertEquals(pe.isBeforeInsertion(), tester.isBeforeInsertion);
      Assert.assertEquals(pe.isAfterInsertion(), tester.isAfterInsertion);
      Assert.assertEquals(pe.isNextToSoftClip(), tester.isNextToSoftClip);
      Assert.assertEquals(pe.getOffset(), tester.getCurrentReadOffset());
    }
  }
  @Test
  public void testIndelsInRegularPileup() {
    final byte[] bases = new byte[] {'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'};
    final byte[] indelBases =
        new byte[] {'A', 'A', 'A', 'A', 'C', 'T', 'A', 'A', 'A', 'A', 'A', 'A'};

    // create a test version of the Reads object
    ReadProperties readAttributes = createTestReadProperties();

    SAMRecord before = ArtificialSAMUtils.createArtificialRead(header, "before", 0, 1, 10);
    before.setReadBases(bases);
    before.setBaseQualities(new byte[] {20, 20, 20, 20, 20, 20, 20, 20, 20, 20});
    before.setCigarString("10M");

    SAMRecord during = ArtificialSAMUtils.createArtificialRead(header, "during", 0, 2, 10);
    during.setReadBases(indelBases);
    during.setBaseQualities(new byte[] {20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20});
    during.setCigarString("4M2I6M");

    SAMRecord after = ArtificialSAMUtils.createArtificialRead(header, "after", 0, 3, 10);
    after.setReadBases(bases);
    after.setBaseQualities(new byte[] {20, 20, 20, 20, 20, 20, 20, 20, 20, 20});
    after.setCigarString("10M");

    List<SAMRecord> reads = Arrays.asList(before, during, after);

    // create the iterator by state with the fake reads and fake records
    li = makeLTBS(reads, readAttributes);

    boolean foundIndel = false;
    while (li.hasNext()) {
      AlignmentContext context = li.next();
      ReadBackedPileup pileup = context.getBasePileup().getBaseFilteredPileup(10);
      for (PileupElement p : pileup) {
        if (p.isBeforeInsertion()) {
          foundIndel = true;
          Assert.assertEquals(p.getEventLength(), 2, "Wrong event length");
          Assert.assertEquals(p.getEventBases(), "CT", "Inserted bases are incorrect");
          break;
        }
      }
    }

    Assert.assertTrue(foundIndel, "Indel in pileup not found");
  }
  /**
   * Test to make sure that reads supporting only an indel (example cigar string: 76I) are
   * represented properly
   */
  @Test
  public void testWholeIndelReadRepresentedTest() {
    final int firstLocus = 44367788, secondLocus = firstLocus + 1;

    SAMRecord read1 = ArtificialSAMUtils.createArtificialRead(header, "read1", 0, secondLocus, 1);
    read1.setReadBases(Utils.dupBytes((byte) 'A', 1));
    read1.setBaseQualities(Utils.dupBytes((byte) '@', 1));
    read1.setCigarString("1I");

    List<SAMRecord> reads = Arrays.asList(read1);

    // create the iterator by state with the fake reads and fake records
    li = makeLTBS(reads, createTestReadProperties());

    while (li.hasNext()) {
      AlignmentContext alignmentContext = li.next();
      ReadBackedPileup p = alignmentContext.getBasePileup();
      Assert.assertTrue(p.getNumberOfElements() == 1);
      PileupElement pe = p.iterator().next();
      Assert.assertTrue(pe.isBeforeInsertion());
      Assert.assertFalse(pe.isAfterInsertion());
      Assert.assertEquals(pe.getEventBases(), "A");
    }

    SAMRecord read2 = ArtificialSAMUtils.createArtificialRead(header, "read2", 0, secondLocus, 10);
    read2.setReadBases(Utils.dupBytes((byte) 'A', 10));
    read2.setBaseQualities(Utils.dupBytes((byte) '@', 10));
    read2.setCigarString("10I");

    reads = Arrays.asList(read2);

    // create the iterator by state with the fake reads and fake records
    li = makeLTBS(reads, createTestReadProperties());

    while (li.hasNext()) {
      AlignmentContext alignmentContext = li.next();
      ReadBackedPileup p = alignmentContext.getBasePileup();
      Assert.assertTrue(p.getNumberOfElements() == 1);
      PileupElement pe = p.iterator().next();
      Assert.assertTrue(pe.isBeforeInsertion());
      Assert.assertFalse(pe.isAfterInsertion());
      Assert.assertEquals(pe.getEventBases(), "AAAAAAAAAA");
    }
  }
  @Test
  public void testXandEQOperators() {
    final byte[] bases1 = new byte[] {'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'};
    final byte[] bases2 = new byte[] {'A', 'A', 'A', 'C', 'A', 'A', 'A', 'A', 'A', 'C'};

    // create a test version of the Reads object
    ReadProperties readAttributes = createTestReadProperties();

    SAMRecord r1 = ArtificialSAMUtils.createArtificialRead(header, "r1", 0, 1, 10);
    r1.setReadBases(bases1);
    r1.setBaseQualities(new byte[] {20, 20, 20, 20, 20, 20, 20, 20, 20, 20});
    r1.setCigarString("10M");

    SAMRecord r2 = ArtificialSAMUtils.createArtificialRead(header, "r2", 0, 1, 10);
    r2.setReadBases(bases2);
    r2.setBaseQualities(new byte[] {20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20});
    r2.setCigarString("3=1X5=1X");

    SAMRecord r3 = ArtificialSAMUtils.createArtificialRead(header, "r3", 0, 1, 10);
    r3.setReadBases(bases2);
    r3.setBaseQualities(new byte[] {20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20});
    r3.setCigarString("3=1X5M1X");

    SAMRecord r4 = ArtificialSAMUtils.createArtificialRead(header, "r4", 0, 1, 10);
    r4.setReadBases(bases2);
    r4.setBaseQualities(new byte[] {20, 20, 20, 20, 20, 20, 20, 20, 20, 20});
    r4.setCigarString("10M");

    List<SAMRecord> reads = Arrays.asList(r1, r2, r3, r4);

    // create the iterator by state with the fake reads and fake records
    li = makeLTBS(reads, readAttributes);

    while (li.hasNext()) {
      AlignmentContext context = li.next();
      ReadBackedPileup pileup = context.getBasePileup();
      Assert.assertEquals(pileup.depthOfCoverage(), 4);
    }
  }
  @BeforeClass
  private void init() throws IOException {
    reference = new CachingIndexedFastaSequenceFile(new File(b37KGReference));
    dictionary = reference.getSequenceDictionary();
    genomeLocParser = new GenomeLocParser(dictionary);
    header = ArtificialSAMUtils.createDefaultReadGroup(new SAMFileHeader(), "test", "test");
    header.setSequenceDictionary(dictionary);
    header.setSortOrder(SAMFileHeader.SortOrder.coordinate);
    readGroup = new GATKSAMReadGroupRecord(header.getReadGroup("test"));

    final List<GATKSAMRecord> reads = new ArrayList<>();
    for (final String contig : contigs) {
      for (int i = 1; i <= numReadsPerContig; i++) {
        reads.add(buildSAMRecord("read" + contig + "_" + i, contig, i));
      }
    }

    createBAM(reads);
  }
 @BeforeClass
 public void beforeClass() {
   header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000);
   genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
 }
  /**
   * Test to make sure that reads supporting only an indel (example cigar string: 76I) do not
   * negatively influence the ordering of the pileup.
   */
  @Test
  public void testWholeIndelRead() {
    final int firstLocus = 44367788, secondLocus = firstLocus + 1;

    SAMRecord leadingRead =
        ArtificialSAMUtils.createArtificialRead(header, "leading", 0, firstLocus, 76);
    leadingRead.setReadBases(Utils.dupBytes((byte) 'A', 76));
    leadingRead.setBaseQualities(Utils.dupBytes((byte) '@', 76));
    leadingRead.setCigarString("1M75I");

    SAMRecord indelOnlyRead =
        ArtificialSAMUtils.createArtificialRead(header, "indelOnly", 0, secondLocus, 76);
    indelOnlyRead.setReadBases(Utils.dupBytes((byte) 'A', 76));
    indelOnlyRead.setBaseQualities(Utils.dupBytes((byte) '@', 76));
    indelOnlyRead.setCigarString("76I");

    SAMRecord fullMatchAfterIndel =
        ArtificialSAMUtils.createArtificialRead(header, "fullMatch", 0, secondLocus, 76);
    fullMatchAfterIndel.setReadBases(Utils.dupBytes((byte) 'A', 76));
    fullMatchAfterIndel.setBaseQualities(Utils.dupBytes((byte) '@', 76));
    fullMatchAfterIndel.setCigarString("75I1M");

    List<SAMRecord> reads = Arrays.asList(leadingRead, indelOnlyRead, fullMatchAfterIndel);

    // create the iterator by state with the fake reads and fake records
    li = makeLTBS(reads, createTestReadProperties());
    int currentLocus = firstLocus;
    int numAlignmentContextsFound = 0;

    while (li.hasNext()) {
      AlignmentContext alignmentContext = li.next();
      Assert.assertEquals(
          alignmentContext.getLocation().getStart(),
          currentLocus,
          "Current locus returned by alignment context is incorrect");

      if (currentLocus == firstLocus) {
        List<GATKSAMRecord> readsAtLocus = alignmentContext.getBasePileup().getReads();
        Assert.assertEquals(
            readsAtLocus.size(), 1, "Wrong number of reads at locus " + currentLocus);
        Assert.assertSame(
            readsAtLocus.get(0),
            leadingRead,
            "leadingRead absent from pileup at locus " + currentLocus);
      } else if (currentLocus == secondLocus) {
        List<GATKSAMRecord> readsAtLocus = alignmentContext.getBasePileup().getReads();
        Assert.assertEquals(
            readsAtLocus.size(), 2, "Wrong number of reads at locus " + currentLocus);
        Assert.assertSame(
            readsAtLocus.get(0),
            indelOnlyRead,
            "indelOnlyRead absent from pileup at locus " + currentLocus);
        Assert.assertSame(
            readsAtLocus.get(1),
            fullMatchAfterIndel,
            "fullMatchAfterIndel absent from pileup at locus " + currentLocus);
      }

      currentLocus++;
      numAlignmentContextsFound++;
    }

    Assert.assertEquals(
        numAlignmentContextsFound, 2, "Found incorrect number of alignment contexts");
  }
/**
 * @author aaron
 * @version 1.0
 *     <p>Class GenomeLocSetTest
 *     <p>This tests the functions of the GenomeLocSet
 */
public class GenomeLocSortedSetUnitTest extends BaseTest {

  private GenomeLocSortedSet mSortedSet = null;
  private SAMFileHeader header =
      ArtificialSAMUtils.createArtificialSamHeader(
          NUMBER_OF_CHROMOSOMES, STARTING_CHROMOSOME, CHROMOSOME_SIZE);
  private static final int NUMBER_OF_CHROMOSOMES = 5;
  private static final int STARTING_CHROMOSOME = 1;
  private static final int CHROMOSOME_SIZE = 1000;

  private GenomeLocParser genomeLocParser;
  private String contigOneName;

  @BeforeClass
  public void setup() {
    genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
    contigOneName = header.getSequenceDictionary().getSequence(1).getSequenceName();
  }

  @BeforeMethod
  public void initializeSortedSet() {
    mSortedSet = new GenomeLocSortedSet(genomeLocParser);
  }

  @Test
  public void testAdd() {
    GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 0, 0);
    assertTrue(mSortedSet.size() == 0);
    mSortedSet.add(g);
    assertTrue(mSortedSet.size() == 1);
  }

  @Test
  public void testRemove() {
    assertTrue(mSortedSet.size() == 0);
    GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 0, 0);
    mSortedSet.add(g);
    assertTrue(mSortedSet.size() == 1);
    mSortedSet.remove(g);
    assertTrue(mSortedSet.size() == 0);
  }

  @Test
  public void addRegion() {
    assertTrue(mSortedSet.size() == 0);
    GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 1, 50);
    mSortedSet.add(g);
    GenomeLoc f = genomeLocParser.createGenomeLoc(contigOneName, 30, 80);
    mSortedSet.addRegion(f);
    assertTrue(mSortedSet.size() == 1);
  }

  @Test
  public void addRegionsOutOfOrder() {
    final String contigTwoName = header.getSequenceDictionary().getSequence(2).getSequenceName();
    assertTrue(mSortedSet.size() == 0);
    GenomeLoc g = genomeLocParser.createGenomeLoc(contigTwoName, 1, 50);
    mSortedSet.add(g);
    GenomeLoc f = genomeLocParser.createGenomeLoc(contigOneName, 30, 80);
    mSortedSet.addRegion(f);
    assertTrue(mSortedSet.size() == 2);
    assertTrue(mSortedSet.toList().get(0).getContig().equals(contigOneName));
    assertTrue(mSortedSet.toList().get(1).getContig().equals(contigTwoName));
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void addThrowsException() {
    assertTrue(mSortedSet.size() == 0);
    GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 1, 50);
    mSortedSet.add(g);
    GenomeLoc f = genomeLocParser.createGenomeLoc(contigOneName, 30, 80);
    mSortedSet.add(f);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testAddDuplicate() {
    assertTrue(mSortedSet.size() == 0);
    GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 0, 0);
    mSortedSet.add(g);
    assertTrue(mSortedSet.size() == 1);
    mSortedSet.add(g);
  }

  @Test
  public void mergingOverlappingBelow() {
    GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 0, 50);
    GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 49, 100);
    assertTrue(mSortedSet.size() == 0);
    mSortedSet.add(g);
    assertTrue(mSortedSet.size() == 1);
    mSortedSet.addRegion(e);
    assertTrue(mSortedSet.size() == 1);
    Iterator<GenomeLoc> iter = mSortedSet.iterator();
    GenomeLoc loc = iter.next();
    assertEquals(loc.getStart(), 0);
    assertEquals(loc.getStop(), 100);
    assertEquals(loc.getContigIndex(), 1);
  }

  @Test
  public void overlap() {
    for (int i = 1; i < 6; i++) {
      final int start = i * 10;
      mSortedSet.add(genomeLocParser.createGenomeLoc(contigOneName, start, start + 1));
    }

    // test matches in and around interval
    assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 9, 9)));
    assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 10, 10)));
    assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 11, 11)));
    assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 12, 12)));

    // test matches spanning intervals
    assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 14, 20)));
    assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 11, 15)));
    assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 30, 40)));
    assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 51, 53)));

    // test miss
    assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 12, 19)));

    // test exact match after miss
    assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 40, 41)));

    // test matches at beginning of intervals
    assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 5, 6)));
    assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 0, 10)));

    // test matches at end of intervals
    assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 52, 53)));
    assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 51, 53)));
    assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 52, 53)));
  }

  @Test
  public void mergingOverlappingAbove() {
    GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 0, 50);
    GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 49, 100);
    assertTrue(mSortedSet.size() == 0);
    mSortedSet.add(g);
    assertTrue(mSortedSet.size() == 1);
    mSortedSet.addRegion(e);
    assertTrue(mSortedSet.size() == 1);
    Iterator<GenomeLoc> iter = mSortedSet.iterator();
    GenomeLoc loc = iter.next();
    assertEquals(loc.getStart(), 0);
    assertEquals(loc.getStop(), 100);
    assertEquals(loc.getContigIndex(), 1);
  }

  @Test
  public void deleteAllByRegion() {
    GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 1, 100);
    mSortedSet.add(e);
    for (int x = 1; x < 101; x++) {
      GenomeLoc del = genomeLocParser.createGenomeLoc(contigOneName, x, x);
      mSortedSet = mSortedSet.subtractRegions(new GenomeLocSortedSet(genomeLocParser, del));
    }
    assertTrue(mSortedSet.isEmpty());
  }

  @Test
  public void deleteSomeByRegion() {
    GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 1, 100);
    mSortedSet.add(e);
    for (int x = 1; x < 50; x++) {
      GenomeLoc del = genomeLocParser.createGenomeLoc(contigOneName, x, x);
      mSortedSet = mSortedSet.subtractRegions(new GenomeLocSortedSet(genomeLocParser, del));
    }
    assertTrue(!mSortedSet.isEmpty());
    assertTrue(mSortedSet.size() == 1);
    GenomeLoc loc = mSortedSet.iterator().next();
    assertTrue(loc.getStop() == 100);
    assertTrue(loc.getStart() == 50);
  }

  @Test
  public void deleteSuperRegion() {
    GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 10, 20);
    GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 70, 100);
    mSortedSet.add(g);
    mSortedSet.addRegion(e);
    assertTrue(mSortedSet.size() == 2);
    // now delete a region
    GenomeLoc d = genomeLocParser.createGenomeLoc(contigOneName, 15, 75);
    mSortedSet = mSortedSet.subtractRegions(new GenomeLocSortedSet(genomeLocParser, d));
    Iterator<GenomeLoc> iter = mSortedSet.iterator();
    GenomeLoc loc = iter.next();
    assertTrue(loc.getStart() == 10);
    assertTrue(loc.getStop() == 14);
    assertTrue(loc.getContigIndex() == 1);

    loc = iter.next();
    assertTrue(loc.getStart() == 76);
    assertTrue(loc.getStop() == 100);
    assertTrue(loc.getContigIndex() == 1);
  }

  @Test
  public void substractComplexExample() {
    GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 1, 20);
    mSortedSet.add(e);

    GenomeLoc r1 = genomeLocParser.createGenomeLoc(contigOneName, 3, 5);
    GenomeLoc r2 = genomeLocParser.createGenomeLoc(contigOneName, 10, 12);
    GenomeLoc r3 = genomeLocParser.createGenomeLoc(contigOneName, 16, 18);
    GenomeLocSortedSet toExclude =
        new GenomeLocSortedSet(genomeLocParser, Arrays.asList(r1, r2, r3));

    GenomeLocSortedSet remaining = mSortedSet.subtractRegions(toExclude);
    //        logger.debug("Initial   " + mSortedSet);
    //        logger.debug("Exclude   " + toExclude);
    //        logger.debug("Remaining " + remaining);

    assertEquals(mSortedSet.coveredSize(), 20);
    assertEquals(toExclude.coveredSize(), 9);
    assertEquals(remaining.coveredSize(), 11);

    Iterator<GenomeLoc> it = remaining.iterator();
    GenomeLoc p1 = it.next();
    GenomeLoc p2 = it.next();
    GenomeLoc p3 = it.next();
    GenomeLoc p4 = it.next();

    assertEquals(genomeLocParser.createGenomeLoc(contigOneName, 1, 2), p1);
    assertEquals(genomeLocParser.createGenomeLoc(contigOneName, 6, 9), p2);
    assertEquals(genomeLocParser.createGenomeLoc(contigOneName, 13, 15), p3);
    assertEquals(genomeLocParser.createGenomeLoc(contigOneName, 19, 20), p4);
  }

  private void testSizeBeforeLocX(int pos, int size) {
    GenomeLoc test = genomeLocParser.createGenomeLoc(contigOneName, pos, pos);
    assertEquals(
        mSortedSet.sizeBeforeLoc(test), size, String.format("X pos=%d size=%d", pos, size));
  }

  @Test
  public void testSizeBeforeLoc() {
    GenomeLoc r1 = genomeLocParser.createGenomeLoc(contigOneName, 3, 5);
    GenomeLoc r2 = genomeLocParser.createGenomeLoc(contigOneName, 10, 12);
    GenomeLoc r3 = genomeLocParser.createGenomeLoc(contigOneName, 16, 18);
    mSortedSet.addAll(Arrays.asList(r1, r2, r3));

    testSizeBeforeLocX(2, 0);
    testSizeBeforeLocX(3, 0);
    testSizeBeforeLocX(4, 1);
    testSizeBeforeLocX(5, 2);
    testSizeBeforeLocX(6, 3);

    testSizeBeforeLocX(10, 3);
    testSizeBeforeLocX(11, 4);
    testSizeBeforeLocX(12, 5);
    testSizeBeforeLocX(13, 6);
    testSizeBeforeLocX(15, 6);

    testSizeBeforeLocX(16, 6);
    testSizeBeforeLocX(17, 7);
    testSizeBeforeLocX(18, 8);
    testSizeBeforeLocX(19, 9);
    testSizeBeforeLocX(50, 9);
    testSizeBeforeLocX(50, (int) mSortedSet.coveredSize());
  }

  @Test
  public void fromSequenceDictionary() {
    mSortedSet =
        GenomeLocSortedSet.createSetFromSequenceDictionary(this.header.getSequenceDictionary());
    // we should have sequence
    assertTrue(mSortedSet.size() == GenomeLocSortedSetUnitTest.NUMBER_OF_CHROMOSOMES);
    int seqNumber = 0;
    for (GenomeLoc loc : mSortedSet) {
      assertTrue(loc.getStart() == 1);
      assertTrue(loc.getStop() == GenomeLocSortedSetUnitTest.CHROMOSOME_SIZE);
      assertTrue(loc.getContigIndex() == seqNumber);
      ++seqNumber;
    }
    assertTrue(seqNumber == GenomeLocSortedSetUnitTest.NUMBER_OF_CHROMOSOMES);
  }

  // -----------------------------------------------------------------------------------------------
  //
  // Test getOverlapping
  //
  // -----------------------------------------------------------------------------------------------

  @DataProvider(name = "GetOverlapping")
  public Object[][] makeGetOverlappingTest() throws Exception {
    final GenomeLocParser genomeLocParser =
        new GenomeLocParser(new CachingIndexedFastaSequenceFile(new File(b37KGReference)));

    List<Object[]> tests = new ArrayList<Object[]>();

    final GenomeLoc prev1 = genomeLocParser.createGenomeLoc("19", 1, 10);
    final GenomeLoc prev2 = genomeLocParser.createGenomeLoc("19", 20, 50);
    final GenomeLoc post1 = genomeLocParser.createGenomeLoc("21", 1, 10);
    final GenomeLoc post2 = genomeLocParser.createGenomeLoc("21", 20, 50);

    final int chr20Length = genomeLocParser.getContigs().getSequence("20").getSequenceLength();
    for (final int regionStart : Arrays.asList(1, 10, chr20Length - 10, chr20Length)) {
      for (final int regionSize : Arrays.asList(1, 10, 100)) {
        final GenomeLoc region =
            genomeLocParser.createGenomeLocOnContig("20", regionStart, regionStart + regionSize);
        final GenomeLoc spanning =
            genomeLocParser.createGenomeLocOnContig("20", regionStart - 10, region.getStop() + 10);
        final GenomeLoc before_into =
            genomeLocParser.createGenomeLocOnContig("20", regionStart - 10, regionStart + 1);
        final GenomeLoc middle =
            genomeLocParser.createGenomeLocOnContig("20", regionStart + 1, regionStart + 2);
        final GenomeLoc middle_past =
            genomeLocParser.createGenomeLocOnContig(
                "20", region.getStop() - 1, region.getStop() + 10);

        final List<GenomeLoc> potentials = new LinkedList<GenomeLoc>();
        potentials.add(region);
        if (spanning != null) potentials.add(spanning);
        if (before_into != null) potentials.add(before_into);
        if (middle != null) potentials.add(middle);
        if (middle_past != null) potentials.add(middle_past);

        for (final int n : Arrays.asList(1, 2, 3)) {
          for (final List<GenomeLoc> regions : Utils.makePermutations(potentials, n, false)) {
            tests.add(new Object[] {new GenomeLocSortedSet(genomeLocParser, regions), region});
            tests.add(
                new Object[] {
                  new GenomeLocSortedSet(genomeLocParser, Utils.append(regions, prev1)), region
                });
            tests.add(
                new Object[] {
                  new GenomeLocSortedSet(genomeLocParser, Utils.append(regions, prev1, prev2)),
                  region
                });
            tests.add(
                new Object[] {
                  new GenomeLocSortedSet(genomeLocParser, Utils.append(regions, post1)), region
                });
            tests.add(
                new Object[] {
                  new GenomeLocSortedSet(genomeLocParser, Utils.append(regions, post1, post2)),
                  region
                });
            tests.add(
                new Object[] {
                  new GenomeLocSortedSet(genomeLocParser, Utils.append(regions, prev1, post1)),
                  region
                });
            tests.add(
                new Object[] {
                  new GenomeLocSortedSet(
                      genomeLocParser, Utils.append(regions, prev1, prev2, post1, post2)),
                  region
                });
          }
        }
      }
    }

    return tests.toArray(new Object[][] {});
  }

  @Test(dataProvider = "GetOverlapping")
  public void testGetOverlapping(final GenomeLocSortedSet intervals, final GenomeLoc region) {
    final List<GenomeLoc> expectedOverlapping = intervals.getOverlappingFullSearch(region);
    final List<GenomeLoc> actualOverlapping = intervals.getOverlapping(region);
    Assert.assertEquals(actualOverlapping, expectedOverlapping);
    Assert.assertEquals(
        intervals.overlaps(region),
        !expectedOverlapping.isEmpty(),
        "GenomeLocSortedSet.overlaps didn't return expected result");
  }
}