/* * The MIT License * * Copyright (c) 2010 The Broad Institute * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package htsjdk.samtools.util; import htsjdk.samtools.Cigar; import htsjdk.samtools.CigarElement; import htsjdk.samtools.TextCigarCodec; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Basic positive tests for testing cigar string clipping * * @author Martha Borkan mborkan@broadinstitute.org */ public class CigarUtilTest { TextCigarCodec codec = TextCigarCodec.getSingleton(); @Test(dataProvider="clipData") public void basicTest(final String testName, final int start, final String inputCigar, final boolean negativeStrand, final int clipPosition, final String expectedCigar, final int expectedAdjustedStart) throws IOException { List<CigarElement> cigar = codec.decode(inputCigar).getCigarElements(); if (negativeStrand){ List<CigarElement> copiedList = new ArrayList<CigarElement>(cigar); Collections.reverse(copiedList); cigar = copiedList; } List<CigarElement> result = CigarUtil.softClipEndOfRead(clipPosition, cigar); Cigar newCigar = new Cigar(result); Cigar oldCigar = new Cigar(cigar); if (negativeStrand){ Collections.reverse(result); newCigar = new Cigar(result); int oldLength = oldCigar.getReferenceLength(); int newLength = newCigar.getReferenceLength(); int sizeChange = oldLength - newLength; //Assert.assertEquals(sizeChange, numClippedBases + adjustment, testName + " sizeChange == numClippedBases"); Assert.assertEquals(start + sizeChange, expectedAdjustedStart, sizeChange + " " + testName); Assert.assertTrue(sizeChange >= 0, "sizeChange >= 0. " + sizeChange); } Assert.assertEquals (codec.encode(newCigar), expectedCigar, testName); Assert.assertEquals(newCigar.getReadLength(), oldCigar.getReadLength()); Assert.assertNull(newCigar.isValid(testName, -1)); } @DataProvider(name = "clipData") private Object[][] getCigarClippingTestData() { // numClippedBases = (readLength - clipPosition) +1 return new Object[][]{ {"Test 1:simple + strand", 100, "50M", false, 43, "42M8S", 100}, {"Test 1s:+ strand already clipped", 100, "42M8S", false, 43, "42M8S", 100}, {"Test 2:simple - strand", 100, "50M", true, 41, "10S40M", 110}, {"Test 3:boundary + strand", 100, "42M3D8M", false, 43, "42M8S", 100}, {"Test 3s:boundary + strand", 100, "42M3D8S", false, 43, "42M8S", 100}, {"Test 3x:stutter + strand", 100, "42M2D1D8M", false, 43, "42M8S", 100}, {"Test 3y:stutter + strand", 100, "42M1D2D8M", false, 43, "42M8S", 100}, {"Test 3a:boundary + strand", 100, "42M1D8M", false, 43, "42M8S", 100}, {"Test 4:boundary - strand", 98, "10M2D40M", true, 41, "10S40M", 110}, {"Test 5:deletion + strand", 100, "44M1D6M", false, 43, "42M8S", 110}, {"Test 6:deletion - strand", 98, "6M2D44M", true, 41, "10S40M", 110}, {"Test 7:insertion + strand", 100, "42M3I5M", false, 43, "42M8S", 100}, {"Test 8:insertion - strand", 102, "8M2I40M", true, 41, "10S40M", 110}, {"Test 9:insertion within + strand", 100, "44M2I4M", false, 43, "42M8S", 100}, {"Test 9x:insertion stutter within + strand", 100, "44M2I2I2M", false, 43, "42M8S", 100}, {"Test 10:insertion within - strand", 100, "3M3I44M", true, 41, "10S40M", 107}, {"Test 11:insertion straddling + strand", 100, "40M4I6M", false, 43, "40M10S", 100}, {"Test 11s:insertion straddling + strand", 100, "40M4I6S", false, 43, "40M10S", 100}, {"Test 11a:insertion straddling + strand", 100, "40M2I8M", false, 43, "40M10S", 100}, {"Test 12:insertion straddling - strand", 104, "4M4I42M", true, 41, "10S40M", 110}, {"Test 12a:insertion straddling - strand", 102, "8M2I40M", true, 41, "10S40M", 110}, {"Test 13:deletion before clip + strand", 100, "10M5D35M", false, 38, "10M5D27M8S", 100}, {"Test 14:deletion before clip - strand", 100, "35M5D10M", true, 36, "10S25M5D10M", 110}, {"Test 15:insertion before clip + strand", 100, "10M5I35M", false, 43, "10M5I27M8S", 100}, {"Test 16:insertion before clip - strand", 100, "16M5I29M", true, 41, "10S6M5I29M", 110}, {"Test 17:second, earlier clip", 100, "48M2S", false, 43, "42M8S", 100}, {"Test 17s:second, earlier clip", 100, "2S48M", true, 43, "8S42M", 106}, {"Test 18:second, later clip", 100, "42M8S", false, 48, "42M8S", 100}, {"Test 18s:second, later clip", 100, "8S42M", true, 48, "8S42M", 100}, }; } @Test(dataProvider="addData") public void addingSoftClippedBasesTest(final String testName, final String cigar, final boolean negativeStrand, final int threePrimeEnd, final int fivePrimeEnd, final String expectedCigar) throws IOException { Assert.assertEquals(CigarUtil.addSoftClippedBasesToEndsOfCigar(codec.decode(cigar), negativeStrand, threePrimeEnd, fivePrimeEnd).toString(), expectedCigar, testName); } @DataProvider(name = "addData") private Object[][] getCigarAddingTestData() { // numClippedBases = (readLength - clipPosition) +1 return new Object[][]{ {"Add to 5' end only, +", "36M", false, 0, 5, "5S36M"}, {"Add to 5' end only, -", "30M1I5M", true, 0, 5, "30M1I5M5S"}, {"Add to 3' end only, +", "26M", false, 3, 0, "26M3S"}, {"Add to 3' end only, -", "19M3D7M", true, 3, 0, "3S19M3D7M"}, {"Add to 5' end already soft-clipped, +", "6S20M", false, 0, 5, "11S20M"}, {"Add to 5' end already soft-clipped, -", "28M4S", true, 0, 5, "28M9S"}, {"Add to 3' end already soft-clipped, +", "15M5I10M2S", false, 7, 0, "15M5I10M9S"}, {"Add to 3' end already soft-clipped, -", "2S34M", true, 6, 0, "8S34M"}, {"Add to 5' and 3' ends, no merging, +", "36M", false, 15, 30, "30S36M15S"}, {"Add to 5' and 3' ends, no merging, -", "36M", true, 15, 30, "15S36M30S"}, {"Add to 5' and 3' ends, merging 5' end, +", "5S31M", false, 15, 30, "35S31M15S"}, {"Add to 5' and 3' ends, merging 5' end, -", "31M5S", true, 15, 30, "15S31M35S"}, {"Add to 5' and 3' ends, merging 3' end, +", "20M6S", false, 10, 12, "12S20M16S"}, {"Add to 5' and 3' ends, merging 3' end, -", "6S25M", true, 10, 12, "16S25M12S"}, {"Add to 5' and 3' ends, merging both ends, +", "3S31M2S", false, 10, 15, "18S31M12S"}, {"Add to 5' and 3' ends, merging both ends, -", "2S26M8S", true, 10, 12, "12S26M20S"} }; } }