// copied from LocusViewTemplate
  protected GATKSAMRecord buildSAMRecord(
      final String readName, final String contig, final int alignmentStart) {
    GATKSAMRecord record = new GATKSAMRecord(header);

    record.setReadName(readName);
    record.setReferenceIndex(dictionary.getSequenceIndex(contig));
    record.setAlignmentStart(alignmentStart);

    record.setCigarString("1M");
    record.setReadString("A");
    record.setBaseQualityString("A");
    record.setReadGroup(readGroup);

    return record;
  }
  @Test(dataProvider = "AdaptorGetter")
  public void testGetAdaptorBoundary(final GetAdaptorFunc get) {
    final int fragmentSize = 10;
    final int mateStart = 1000;
    final int BEFORE = mateStart - 2;
    final int AFTER = mateStart + 2;
    int myStart, boundary;
    GATKSAMRecord read;

    // Test case 1: positive strand, first read
    read = makeRead(fragmentSize, mateStart);
    myStart = BEFORE;
    read.setAlignmentStart(myStart);
    read.setReadNegativeStrandFlag(false);
    read.setMateNegativeStrandFlag(true);
    boundary = get.getAdaptor(read);
    Assert.assertEquals(boundary, myStart + fragmentSize + 1);

    // Test case 2: positive strand, second read
    read = makeRead(fragmentSize, mateStart);
    myStart = AFTER;
    read.setAlignmentStart(myStart);
    read.setReadNegativeStrandFlag(false);
    read.setMateNegativeStrandFlag(true);
    boundary = get.getAdaptor(read);
    Assert.assertEquals(boundary, myStart + fragmentSize + 1);

    // Test case 3: negative strand, second read
    read = makeRead(fragmentSize, mateStart);
    myStart = AFTER;
    read.setAlignmentStart(myStart);
    read.setReadNegativeStrandFlag(true);
    read.setMateNegativeStrandFlag(false);
    boundary = get.getAdaptor(read);
    Assert.assertEquals(boundary, mateStart - 1);

    // Test case 4: negative strand, first read
    read = makeRead(fragmentSize, mateStart);
    myStart = BEFORE;
    read.setAlignmentStart(myStart);
    read.setReadNegativeStrandFlag(true);
    read.setMateNegativeStrandFlag(false);
    boundary = get.getAdaptor(read);
    Assert.assertEquals(boundary, mateStart - 1);

    // Test case 5: mate is mapped to another chromosome (test both strands)
    read = makeRead(fragmentSize, mateStart);
    read.setInferredInsertSize(0);
    read.setReadNegativeStrandFlag(true);
    read.setMateNegativeStrandFlag(false);
    boundary = get.getAdaptor(read);
    Assert.assertEquals(boundary, ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);
    read.setReadNegativeStrandFlag(false);
    read.setMateNegativeStrandFlag(true);
    boundary = get.getAdaptor(read);
    Assert.assertEquals(boundary, ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);
    read.setInferredInsertSize(10);

    // Test case 6: read is unmapped
    read = makeRead(fragmentSize, mateStart);
    read.setReadUnmappedFlag(true);
    boundary = get.getAdaptor(read);
    Assert.assertEquals(boundary, ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);
    read.setReadUnmappedFlag(false);

    // Test case 7:  reads don't overlap and look like this:
    //    <--------|
    //                 |------>
    // first read:
    read = makeRead(fragmentSize, mateStart);
    myStart = 980;
    read.setAlignmentStart(myStart);
    read.setInferredInsertSize(20);
    read.setReadNegativeStrandFlag(true);
    boundary = get.getAdaptor(read);
    Assert.assertEquals(boundary, ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);

    // second read:
    read = makeRead(fragmentSize, mateStart);
    myStart = 1000;
    read.setAlignmentStart(myStart);
    read.setInferredInsertSize(20);
    read.setMateAlignmentStart(980);
    read.setReadNegativeStrandFlag(false);
    boundary = get.getAdaptor(read);
    Assert.assertEquals(boundary, ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);

    // Test case 8: read doesn't have proper pair flag set
    read = makeRead(fragmentSize, mateStart);
    read.setReadPairedFlag(true);
    read.setProperPairFlag(false);
    Assert.assertEquals(get.getAdaptor(read), ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);

    // Test case 9: read and mate have same negative flag setting
    for (final boolean negFlag : Arrays.asList(true, false)) {
      read = makeRead(fragmentSize, mateStart);
      read.setAlignmentStart(BEFORE);
      read.setReadPairedFlag(true);
      read.setProperPairFlag(true);
      read.setReadNegativeStrandFlag(negFlag);
      read.setMateNegativeStrandFlag(!negFlag);
      Assert.assertTrue(
          get.getAdaptor(read) != ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY,
          "Get adaptor should have succeeded");

      read = makeRead(fragmentSize, mateStart);
      read.setAlignmentStart(BEFORE);
      read.setReadPairedFlag(true);
      read.setProperPairFlag(true);
      read.setReadNegativeStrandFlag(negFlag);
      read.setMateNegativeStrandFlag(negFlag);
      Assert.assertEquals(
          get.getAdaptor(read),
          ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY,
          "Get adaptor should have failed for reads with bad alignment orientation");
    }
  }
  @DataProvider(name = "HasWellDefinedFragmentSizeData")
  public Object[][] makeHasWellDefinedFragmentSizeData() throws Exception {
    final List<Object[]> tests = new LinkedList<Object[]>();

    // setup a basic read that will work
    final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader();
    final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read1", 0, 10, 10);
    read.setReadPairedFlag(true);
    read.setProperPairFlag(true);
    read.setReadUnmappedFlag(false);
    read.setMateUnmappedFlag(false);
    read.setAlignmentStart(100);
    read.setCigarString("50M");
    read.setMateAlignmentStart(130);
    read.setInferredInsertSize(80);
    read.setFirstOfPairFlag(true);
    read.setReadNegativeStrandFlag(false);
    read.setMateNegativeStrandFlag(true);

    tests.add(new Object[] {"basic case", read.clone(), true});

    {
      final GATKSAMRecord bad1 = (GATKSAMRecord) read.clone();
      bad1.setReadPairedFlag(false);
      tests.add(new Object[] {"not paired", bad1, false});
    }

    {
      final GATKSAMRecord bad = (GATKSAMRecord) read.clone();
      bad.setProperPairFlag(false);
      // we currently don't require the proper pair flag to be set
      tests.add(new Object[] {"not proper pair", bad, true});
      //            tests.add( new Object[]{ "not proper pair", bad, false });
    }

    {
      final GATKSAMRecord bad = (GATKSAMRecord) read.clone();
      bad.setReadUnmappedFlag(true);
      tests.add(new Object[] {"read is unmapped", bad, false});
    }

    {
      final GATKSAMRecord bad = (GATKSAMRecord) read.clone();
      bad.setMateUnmappedFlag(true);
      tests.add(new Object[] {"mate is unmapped", bad, false});
    }

    {
      final GATKSAMRecord bad = (GATKSAMRecord) read.clone();
      bad.setMateNegativeStrandFlag(false);
      tests.add(new Object[] {"read and mate both on positive strand", bad, false});
    }

    {
      final GATKSAMRecord bad = (GATKSAMRecord) read.clone();
      bad.setReadNegativeStrandFlag(true);
      tests.add(new Object[] {"read and mate both on negative strand", bad, false});
    }

    {
      final GATKSAMRecord bad = (GATKSAMRecord) read.clone();
      bad.setInferredInsertSize(0);
      tests.add(new Object[] {"insert size is 0", bad, false});
    }

    {
      final GATKSAMRecord bad = (GATKSAMRecord) read.clone();
      bad.setAlignmentStart(1000);
      tests.add(new Object[] {"positve read starts after mate end", bad, false});
    }

    {
      final GATKSAMRecord bad = (GATKSAMRecord) read.clone();
      bad.setReadNegativeStrandFlag(true);
      bad.setMateNegativeStrandFlag(false);
      bad.setMateAlignmentStart(1000);
      tests.add(new Object[] {"negative strand read ends before mate starts", bad, false});
    }

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