/* * Copyright (c) 2012 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.variant.bcf2; import htsjdk.variant.VariantBaseTest; import htsjdk.variant.utils.GeneralUtils; import htsjdk.variant.vcf.VCFContigHeaderLine; import htsjdk.variant.vcf.VCFFilterHeaderLine; import htsjdk.variant.vcf.VCFFormatHeaderLine; import htsjdk.variant.vcf.VCFHeader; import htsjdk.variant.vcf.VCFHeaderLine; import htsjdk.variant.vcf.VCFHeaderLineCount; import htsjdk.variant.vcf.VCFHeaderLineType; import htsjdk.variant.vcf.VCFIDHeaderLine; import htsjdk.variant.vcf.VCFInfoHeaderLine; import htsjdk.variant.vcf.VCFSimpleHeaderLine; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; /** * Tests for BCF2Utils */ public final class BCF2UtilsUnitTest extends VariantBaseTest { @DataProvider(name = "CollapseExpandTest") public Object[][] makeCollapseExpandTest() { List<Object[]> tests = new ArrayList<Object[]>(); tests.add(new Object[]{Arrays.asList("A"), "A", false}); tests.add(new Object[]{Arrays.asList("A", "B"), ",A,B", true}); tests.add(new Object[]{Arrays.asList("AB"), "AB", false}); tests.add(new Object[]{Arrays.asList("AB", "C"), ",AB,C", true}); tests.add(new Object[]{Arrays.asList(), "", false}); return tests.toArray(new Object[][]{}); } @Test(dataProvider = "CollapseExpandTest") public void testCollapseExpandTest(final List<String> in, final String expectedCollapsed, final boolean isCollapsed) { final String actualCollapsed = BCF2Utils.collapseStringList(in); Assert.assertEquals(actualCollapsed, expectedCollapsed); Assert.assertEquals(BCF2Utils.isCollapsedString(actualCollapsed), isCollapsed); if ( isCollapsed ) Assert.assertEquals(BCF2Utils.explodeStringList(actualCollapsed), in); } @Test public void testCreateDictionary() { final List<VCFHeaderLine> inputLines = new ArrayList<VCFHeaderLine>(); int counter = 0; inputLines.add(new VCFFilterHeaderLine(String.valueOf(counter++))); inputLines.add(new VCFFilterHeaderLine(String.valueOf(counter++))); inputLines.add(new VCFContigHeaderLine(Collections.singletonMap("ID", String.valueOf(counter++)), counter)); inputLines.add(new VCFContigHeaderLine(Collections.singletonMap("ID", String.valueOf(counter++)), counter)); inputLines.add(new VCFInfoHeaderLine(String.valueOf(counter++), VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "x")); inputLines.add(new VCFInfoHeaderLine(String.valueOf(counter++), VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "x")); inputLines.add(new VCFHeaderLine("x", "misc")); inputLines.add(new VCFHeaderLine("y", "misc")); inputLines.add(new VCFSimpleHeaderLine("GATKCommandLine","z","misc")); inputLines.add(new VCFFormatHeaderLine(String.valueOf(counter++), VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "x")); inputLines.add(new VCFFormatHeaderLine(String.valueOf(counter++), VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "x")); final int inputLineCounter = counter; final VCFHeader inputHeader = new VCFHeader(new LinkedHashSet<VCFHeaderLine>(inputLines)); final ArrayList<String> dict = BCF2Utils.makeDictionary(inputHeader); final int dict_size = dict.size(); Assert.assertEquals(7,dict_size); } @DataProvider(name = "HeaderOrderTestProvider") public Object[][] makeHeaderOrderTestProvider() { final List<VCFHeaderLine> inputLines = new ArrayList<VCFHeaderLine>(); final List<VCFHeaderLine> extraLines = new ArrayList<VCFHeaderLine>(); int counter = 0; inputLines.add(new VCFFilterHeaderLine(String.valueOf(counter++))); inputLines.add(new VCFFilterHeaderLine(String.valueOf(counter++))); inputLines.add(new VCFContigHeaderLine(Collections.singletonMap("ID", String.valueOf(counter++)), counter)); inputLines.add(new VCFContigHeaderLine(Collections.singletonMap("ID", String.valueOf(counter++)), counter)); inputLines.add(new VCFInfoHeaderLine(String.valueOf(counter++), VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "x")); inputLines.add(new VCFInfoHeaderLine(String.valueOf(counter++), VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "x")); inputLines.add(new VCFFormatHeaderLine(String.valueOf(counter++), VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "x")); inputLines.add(new VCFFormatHeaderLine(String.valueOf(counter++), VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "x")); final int inputLineCounter = counter; final VCFHeader inputHeader = new VCFHeader(new LinkedHashSet<VCFHeaderLine>(inputLines)); extraLines.add(new VCFFilterHeaderLine(String.valueOf(counter++))); extraLines.add(new VCFContigHeaderLine(Collections.singletonMap("ID", String.valueOf(counter++)), counter)); extraLines.add(new VCFInfoHeaderLine(String.valueOf(counter++), VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "x")); extraLines.add(new VCFFormatHeaderLine(String.valueOf(counter++), VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "x")); extraLines.add(new VCFHeaderLine("x", "misc")); extraLines.add(new VCFHeaderLine("y", "misc")); List<Object[]> tests = new ArrayList<Object[]>(); for ( final int extrasToTake : Arrays.asList(0, 1, 2, 3) ) { final List<VCFHeaderLine> empty = Collections.emptyList(); final List<List<VCFHeaderLine>> permutations = extrasToTake == 0 ? Collections.singletonList(empty) : GeneralUtils.makePermutations(extraLines, extrasToTake, false); for ( final List<VCFHeaderLine> permutation : permutations ) { for ( int i = -1; i < inputLines.size(); i++ ) { final List<VCFHeaderLine> allLines = new ArrayList<VCFHeaderLine>(inputLines); if ( i >= 0 ) allLines.remove(i); allLines.addAll(permutation); final VCFHeader testHeader = new VCFHeader(new LinkedHashSet<VCFHeaderLine>(allLines)); final boolean expectedConsistent = expectedConsistent(testHeader, inputLineCounter); tests.add(new Object[]{inputHeader, testHeader, expectedConsistent}); } } } // sample name tests final List<List<String>> sampleNameTests = Arrays.asList( new ArrayList<String>(), Arrays.asList("A"), Arrays.asList("A", "B"), Arrays.asList("A", "B", "C")); for ( final List<String> inSamples : sampleNameTests ) { for ( final List<String> testSamples : sampleNameTests ) { final VCFHeader inputHeaderWithSamples = new VCFHeader(inputHeader.getMetaDataInInputOrder(), inSamples); final List<List<String>> permutations = testSamples.isEmpty() ? Collections.singletonList(testSamples) : GeneralUtils.makePermutations(testSamples, testSamples.size(), false); for ( final List<String> testSamplesPermutation : permutations ) { final VCFHeader testHeaderWithSamples = new VCFHeader(inputHeader.getMetaDataInInputOrder(), testSamplesPermutation); final boolean expectedConsistent = testSamples.equals(inSamples); tests.add(new Object[]{inputHeaderWithSamples, testHeaderWithSamples, expectedConsistent}); } } } return tests.toArray(new Object[][]{}); } private static boolean expectedConsistent(final VCFHeader combinationHeader, final int minCounterForInputLines) { final List<Integer> ids = new ArrayList<Integer>(); for ( final VCFHeaderLine line : combinationHeader.getMetaDataInInputOrder() ) { if ( line instanceof VCFIDHeaderLine) { ids.add(Integer.valueOf(((VCFIDHeaderLine) line).getID())); } } // as long as the start contains all of the ids up to minCounterForInputLines in order for ( int i = 0; i < minCounterForInputLines; i++ ) if ( i >= ids.size() || ids.get(i) != i ) return false; return true; } // // Test to make sure that we detect correctly the case where we can preserve the genotypes data in a BCF2 // even when the header file is slightly different // @Test(dataProvider = "HeaderOrderTestProvider") public void testHeaderOrder(final VCFHeader inputHeader, final VCFHeader testHeader, final boolean expectedConsistent) { final boolean actualOrderConsistency = BCF2Utils.headerLinesAreOrderedConsistently(testHeader, inputHeader); Assert.assertEquals(actualOrderConsistency, expectedConsistent); } private void assertListsAreEquivalent(final List<?> a, final List<?> b) { Assert.assertEquals(a.size(), b.size()); for (int i=0; i<a.size(); i++) Assert.assertEquals(a.get(i), b.get(i)); } @DataProvider(name = "toListTestProvider") public Object[][] makeToListTest() { final List<Object[]> tests = new ArrayList<Object[]>(); tests.add(new Object[]{Object.class, null, Collections.emptyList()}); tests.add(new Object[]{Integer.class, 1, Arrays.asList(1)}); tests.add(new Object[]{Integer.class, new int[]{1, 2, 3}, Arrays.asList(1, 2, 3)}); tests.add(new Object[]{String.class, Arrays.asList("X", "Y"), Arrays.asList("X", "Y")}); return tests.toArray(new Object[][]{}); } @Test(dataProvider = "toListTestProvider") public void testToList(final Class<?> cls, final Object input, final List<Object> expectedOutput) { assertListsAreEquivalent(BCF2Utils.toList(cls, input), expectedOutput); } }