package picard.analysis.replicates; import com.google.common.collect.ImmutableMap; import htsjdk.samtools.metrics.MetricsFile; import htsjdk.samtools.util.IOUtil; import htsjdk.samtools.util.TestUtil; import org.testng.Assert; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import picard.sam.MergeSamFiles; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import static org.testng.Assert.assertEquals; /** * Created by farjoun on 6/24/15. */ public class CollectIndependentReplicatesMetricTest { private final static File testdir = new File("testdata/picard/independent_replicates"); private final static File bamOutDir = IOUtil.createTempDir("convertSamToBam", "dir"); private final static Map<String, String> sams = new ImmutableMap.Builder<String, String>() .put("twoPairs", "twopairs.sam") .put("twoPairsWithUMIs", "twopairsWithUMIs.sam") .put("twoPairsWithBadUMIs", "twopairsWithBadUMIs.sam") .put("aTriple", "aTriple.sam") .put("aTripleWithUMIs", "aTripleWithUMIs.sam") .put("multipleContigs", "multipleContigs.sam") .put("twopairsWithUMIsMultipleOrientations","twopairsWithUMIsMultipleOrientations.sam").build(); private final static Map<String, File> bams = new HashMap<>(sams.size()); @BeforeTest public void prepareBams() throws IOException { sams.keySet().stream().forEach(key -> { try { bams.put(key, convertSamToBam(sams.get(key))); bams.get(key).deleteOnExit(); } catch (IOException e) { e.printStackTrace(); } }); bamOutDir.deleteOnExit(); } @AfterTest public void tearDown() { TestUtil.recursiveDelete(bamOutDir); } @DataProvider(name = "simpleTests") public Iterator<Object[]> simpleTestsData() { final List<Object[]> tests = new ArrayList<>(3); { final Map<String, Object> map = new LinkedHashMap<>(); map.put("nSites", 3); map.put("nDuplicateSets", 3); map.put("nMismatchingUMIsInCoOrientedBiDups",2); map.put("nMismatchingUMIsInContraOrientedBiDups",1); tests.add(new Object[]{"multipleContigs.vcf", "twopairsWithUMIsMultipleOrientations", map}); } { final Map<String, Object> map = new LinkedHashMap<>(); map.put("nSites", 1); map.put("nDuplicateSets", 1); map.put("nDifferentAllelesTriDups", 0); map.put("nDifferentAllelesBiDups", 1); map.put("nReferenceAllelesBiDups", 0); map.put("nAlternateAllelesBiDups", 0); map.put("biSiteHeterogeneityRate", 1.0); map.put("biSiteHomogeneityRate", 0.0); map.put("nAlternateReads", 1); map.put("nReferenceReads", 1); tests.add(new Object[]{"hets.vcf", "twoPairs", map}); } {// this tests the GQ cutoff final Map<String, Object> map = new LinkedHashMap<>(); map.put("nDifferentAllelesBiDups", 1); map.put("biSiteHeterogeneityRate", 1.0); map.put("biSiteHomogeneityRate", 0.0); map.put("nDifferentAllelesTriDups", 0); map.put("nSites", 1); tests.add(new Object[]{"twoSamplesHet.vcf", "twoPairs", map}); } { final Map<String, Object> map = new LinkedHashMap<>(); map.put("nExactlyTriple", 1); map.put("nExactlyDouble", 1); map.put("nDuplicateSets", 2); map.put("nAlternateReads", 2); map.put("nReferenceReads", 3); tests.add(new Object[]{"hets.vcf", "aTriple", map}); } { final Map<String, Object> map = new HashMap<>(); map.put("nSites", 4); map.put("nTotalReads", 20); map.put("nDuplicateSets", 8); tests.add(new Object[]{"multipleContigs.vcf", "multipleContigs", map}); } { final Map<String, Object> map = new LinkedHashMap<>(); map.put("nAlternateAllelesTriDups", 1); map.put("nMismatchingAllelesBiDups", 0); //we remove sites that have mismatching alleles, so this should be zero. tests.add(new Object[]{"hets_pos20.vcf", "aTriple", map}); } tests.add(new Object[]{"hets_pos21_HOMREF_G.vcf", "aTriple", Collections.singletonMap("nReferenceAllelesTriDups", 1)}); tests.add(new Object[]{"hets_pos20.vcf", "twoPairs", Collections.singletonMap("nAlternateAllelesBiDups", 1)}); tests.add(new Object[]{"hets_pos21_HOMREF_G.vcf", "twoPairs", Collections.singletonMap("nReferenceAllelesBiDups", 1)}); { final Map<String, Object> map = new LinkedHashMap<>(); map.put("nSites", 1); map.put("nThreeAllelesSites", 1); map.put("nAlternateAllelesTriDups", 0); map.put("nMismatchingAllelesBiDups", 0); //we remove sites that have mismatching alleles, so this should be zero. tests.add(new Object[]{"hets_pos22_IncorrectAlleles.vcf", "twoPairs", map}); } //This tests the BQ cutoff tests.add(new Object[]{"hets_pos22_IncorrectAlleles.vcf", "aTriple", Collections.singletonMap("nMismatchingAllelesTriDups", 0)}); {// tests for UMIs final Map<String, Object> map = new LinkedHashMap<>(); map.put("nSites", 1); map.put("nMismatchingUMIsInDiffBiDups", 1); map.put("nMatchingUMIsInDiffBiDups", 0); map.put("nMismatchingUMIsInSameBiDups", 0); map.put("nMatchingUMIsInSameBiDups", 0); map.put("nGoodBarcodes",1); map.put("nBadBarcodes",0); tests.add(new Object[]{"hets.vcf", "twoPairsWithUMIs", map}); } {// tests for UMIs final Map<String, Object> map = new LinkedHashMap<>(); map.put("nSites", 1); map.put("nMismatchingUMIsInDiffBiDups", 0); map.put("nMatchingUMIsInDiffBiDups", 0); map.put("nMismatchingUMIsInSameBiDups", 0); map.put("nMatchingUMIsInSameBiDups", 0); map.put("nGoodBarcodes",0); map.put("nBadBarcodes",1); tests.add(new Object[]{"hets.vcf", "twoPairsWithBadUMIs", map}); } return tests.iterator(); } @Test(dataProvider = "simpleTests") public void simpleTest(final String vcf, final String bam, final Map<String, Object> fieldValueMap) throws IOException, NoSuchFieldException, IllegalAccessException { final CollectIndependentReplicateMetrics est = new CollectIndependentReplicateMetrics(); est.INPUT = bams.get(bam); est.VCF = new File(testdir, vcf); est.OUTPUT = IOUtil.newTempFile("singleHet", ".duplication_metric", new File[]{bamOutDir}); est.MATRIX_OUTPUT = IOUtil.newTempFile("singleHet", ".duplication_matrix", new File[]{bamOutDir}); est.SAMPLE = "SAMPLE1"; est.OUTPUT.deleteOnExit(); est.MATRIX_OUTPUT.deleteOnExit(); est.doWork(); final MetricsFile<IndependentReplicateMetric, Integer> retval = new MetricsFile<>(); retval.read(new FileReader(est.OUTPUT)); for (final Map.Entry<String, Object> fieldValue : fieldValueMap.entrySet()) { final String field = fieldValue.getKey(); final Object expectedValue = fieldValue.getValue(); final Field o = IndependentReplicateMetric.class.getField(field); assertEquals(o.get(retval.getMetrics().get(0)), expectedValue, field); } } /** * Converts a sam-file to a bam-file changing the extension from .sam to .bam * */ private static File convertSamToBam(final String sam) throws IOException { final MergeSamFiles msf = new MergeSamFiles(); final File bam = new File(bamOutDir, sam.replaceAll("sam$", "bam")); final int returnCode = msf.instanceMain( new String[]{ "INPUT=" + (new File(testdir, sam).getAbsolutePath()), "CREATE_INDEX=true", "OUTPUT=" + bam.getAbsolutePath()}); Assert.assertEquals(returnCode, 0); return bam; } }