/*
* 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.variantcontext;
// the imports for unit testing.
import htsjdk.tribble.util.ParsingUtils;
import htsjdk.variant.VariantBaseTest;
import htsjdk.variant.utils.GeneralUtils;
import org.testng.Assert;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class GenotypesContextUnitTest extends VariantBaseTest {
Allele Aref, C, T;
Genotype AA, AT, TT, AC, CT, CC, MISSING;
List<Genotype> allGenotypes;
@BeforeSuite
public void before() {
C = Allele.create("C");
Aref = Allele.create("A", true);
T = Allele.create("T");
AA = GenotypeBuilder.create("AA", Arrays.asList(Aref, Aref));
AT = GenotypeBuilder.create("AT", Arrays.asList(Aref, T));
TT = GenotypeBuilder.create("TT", Arrays.asList(T, T));
AC = GenotypeBuilder.create("AC", Arrays.asList(Aref, C));
CT = GenotypeBuilder.create("CT", Arrays.asList(C, T));
CC = GenotypeBuilder.create("CC", Arrays.asList(C, C));
MISSING = GenotypeBuilder.create("MISSING", Arrays.asList(C, C));
allGenotypes = Arrays.asList(AA, AT, TT, AC, CT, CC);
}
// --------------------------------------------------------------------------------
//
// Provider
//
// --------------------------------------------------------------------------------
private interface ContextMaker {
public GenotypesContext make(List<Genotype> initialSamples);
}
private ContextMaker baseMaker = new ContextMaker() {
@Override
public GenotypesContext make(final List<Genotype> initialSamples) {
return GenotypesContext.copy(initialSamples);
}
@Override
public String toString() {
return "GenotypesContext";
}
};
private final class lazyMaker implements LazyGenotypesContext.LazyParser, ContextMaker {
@Override
public LazyGenotypesContext.LazyData parse(final Object data) {
GenotypesContext gc = GenotypesContext.copy((List<Genotype>)data);
gc.ensureSampleNameMap();
gc.ensureSampleOrdering();
return new LazyGenotypesContext.LazyData(gc.notToBeDirectlyAccessedGenotypes, gc.sampleNamesInOrder, gc.sampleNameToOffset);
}
@Override
public GenotypesContext make(final List<Genotype> initialSamples) {
return new LazyGenotypesContext(this, initialSamples, initialSamples.size());
}
@Override
public String toString() {
return "LazyGenotypesContext";
}
}
private Collection<ContextMaker> allMakers = Arrays.asList(baseMaker, new lazyMaker());
private class GenotypesContextProvider {
String name;
ContextMaker maker;
final List<Genotype> initialSamples;
private GenotypesContextProvider(ContextMaker maker, List<Genotype> initialSamples) {
this.name = String.format("%s with %d samples", maker.toString(), initialSamples.size());
this.maker = maker;
this.initialSamples = initialSamples;
}
public GenotypesContext makeContext() {
return maker.make(initialSamples);
}
}
@DataProvider(name = "GenotypesContextProvider")
public Object[][] MakeSampleNamesTest() {
List<Object[]> tests = new ArrayList<Object[]>();
for ( ContextMaker maker : allMakers ) {
for ( int i = 0; i < allGenotypes.size(); i++ ) {
List<Genotype> samples = allGenotypes.subList(0, i);
// sorted
tests.add(new Object[]{new GenotypesContextProvider(maker, samples)});
// unsorted
tests.add(new Object[]{new GenotypesContextProvider(maker, GeneralUtils.reverse(samples))});
}
}
return tests.toArray(new Object[][]{});
}
private final static void testIterable(Iterable<Genotype> genotypeIterable, Set<String> expectedNames) {
int count = 0;
for ( final Genotype g : genotypeIterable ) {
Assert.assertTrue(expectedNames.contains(g.getSampleName()));
count++;
}
Assert.assertEquals(count, expectedNames.size(), "Iterable returned unexpected number of genotypes");
}
@Test(dataProvider = "GenotypesContextProvider")
public void testInitialSamplesAreAsExpected(GenotypesContextProvider cfg) {
testGenotypesContextContainsExpectedSamples(cfg.makeContext(), cfg.initialSamples);
}
private final void testGenotypesContextContainsExpectedSamples(GenotypesContext gc, List<Genotype> expectedSamples) {
Assert.assertEquals(gc.isEmpty(), expectedSamples.isEmpty());
Assert.assertEquals(gc.size(), expectedSamples.size());
// get(index) is doing the right thing
for ( int i = 0; i < expectedSamples.size(); i++ ) {
Assert.assertEquals(gc.get(i), expectedSamples.get(i));
}
Assert.assertFalse(gc.containsSample(MISSING.getSampleName()));
// we can fetch samples by name
final Set<String> genotypeNames = VariantContextUtils.genotypeNames(expectedSamples);
for ( final String name : genotypeNames ) {
Assert.assertTrue(gc.containsSample(name));
}
Assert.assertFalse(gc.containsSample(MISSING.getSampleName()));
// all of the iterators are working
testIterable(gc.iterateInSampleNameOrder(), genotypeNames);
testIterable(gc, genotypeNames);
testIterable(gc.iterateInSampleNameOrder(genotypeNames), genotypeNames);
if ( ! genotypeNames.isEmpty() ) {
Set<String> first = Collections.singleton(genotypeNames.iterator().next());
testIterable(gc.iterateInSampleNameOrder(first), first);
}
// misc. utils are working as expected
assertEqualsSet(gc.getSampleNames(), genotypeNames, "gc sample names vs. expected sample names");
Assert.assertTrue(ParsingUtils.isSorted(gc.getSampleNamesOrderedByName()));
Assert.assertTrue(ParsingUtils.isSorted(gc.iterateInSampleNameOrder()));
Assert.assertTrue(gc.containsSamples(genotypeNames));
final Set<String> withMissing = new HashSet<String>(Arrays.asList(MISSING.getSampleName()));
withMissing.addAll(genotypeNames);
Assert.assertFalse(gc.containsSamples(withMissing));
}
@Test(enabled = true, dataProvider = "GenotypesContextProvider")
public void testImmutable(GenotypesContextProvider cfg) {
GenotypesContext gc = cfg.makeContext();
Assert.assertEquals(gc.isMutable(), true);
gc.immutable();
Assert.assertEquals(gc.isMutable(), false);
}
@Test(enabled = true, dataProvider = "GenotypesContextProvider", expectedExceptions = Throwable.class )
public void testImmutableCall1(GenotypesContextProvider cfg) {
GenotypesContext gc = cfg.makeContext();
gc.immutable();
gc.add(MISSING);
}
@Test(enabled = true, dataProvider = "GenotypesContextProvider")
public void testClear(GenotypesContextProvider cfg) {
GenotypesContext gc = cfg.makeContext();
gc.clear();
testGenotypesContextContainsExpectedSamples(gc, Collections.<Genotype>emptyList());
}
private static final List<Genotype> with(List<Genotype> genotypes, Genotype ... add) {
List<Genotype> l = new ArrayList<Genotype>(genotypes);
l.addAll(Arrays.asList(add));
return l;
}
private static final List<Genotype> without(List<Genotype> genotypes, Genotype ... remove) {
List<Genotype> l = new ArrayList<Genotype>(genotypes);
l.removeAll(Arrays.asList(remove));
return l;
}
@Test(enabled = true, dataProvider = "GenotypesContextProvider")
public void testAdds(GenotypesContextProvider cfg) {
Genotype add1 = GenotypeBuilder.create("add1", Arrays.asList(Aref, Aref));
Genotype add2 = GenotypeBuilder.create("add2", Arrays.asList(Aref, Aref));
GenotypesContext gc = cfg.makeContext();
gc.add(add1);
testGenotypesContextContainsExpectedSamples(gc, with(cfg.initialSamples, add1));
gc = cfg.makeContext();
gc.add(add1);
gc.add(add2);
testGenotypesContextContainsExpectedSamples(gc, with(cfg.initialSamples, add1, add2));
gc = cfg.makeContext();
gc.addAll(Arrays.asList(add1, add2));
testGenotypesContextContainsExpectedSamples(gc, with(cfg.initialSamples, add1, add2));
}
@Test(enabled = true, dataProvider = "GenotypesContextProvider")
public void testRemoves(GenotypesContextProvider cfg) {
Genotype rm1 = AA;
Genotype rm2 = AC;
GenotypesContext gc = cfg.makeContext();
if (gc.size() > 1) {
Genotype rm = gc.get(0);
gc.remove(rm);
testGenotypesContextContainsExpectedSamples(gc, without(cfg.initialSamples, rm));
}
gc = cfg.makeContext();
gc.remove(rm1);
testGenotypesContextContainsExpectedSamples(gc, without(cfg.initialSamples, rm1));
gc = cfg.makeContext();
gc.remove(rm1);
gc.remove(rm2);
testGenotypesContextContainsExpectedSamples(gc, without(cfg.initialSamples, rm1, rm2));
gc = cfg.makeContext();
gc.removeAll(Arrays.asList(rm1, rm2));
testGenotypesContextContainsExpectedSamples(gc, without(cfg.initialSamples, rm1, rm2));
gc = cfg.makeContext();
HashSet<Genotype> expected = new HashSet<Genotype>();
if ( gc.contains(rm1) ) expected.add(rm1);
if ( gc.contains(rm2) ) expected.add(rm2);
gc.retainAll(Arrays.asList(rm1, rm2));
// ensure that the two lists are the same
assertEqualsSet(new HashSet<Genotype>(gc.getGenotypes()), expected, "gc genotypes vs. expected");
// because the list order can change, we use the gc's list itself
testGenotypesContextContainsExpectedSamples(gc, gc.getGenotypes());
}
@Test(enabled = true, dataProvider = "GenotypesContextProvider")
public void testSet(GenotypesContextProvider cfg) {
Genotype set = GenotypeBuilder.create("replace", Arrays.asList(Aref, Aref));
int n = cfg.makeContext().size();
for ( int i = 0; i < n; i++ ) {
GenotypesContext gc = cfg.makeContext();
Genotype setted = gc.set(i, set);
Assert.assertNotNull(setted);
ArrayList<Genotype> l = new ArrayList<Genotype>(cfg.initialSamples);
l.set(i, set);
testGenotypesContextContainsExpectedSamples(gc, l);
}
}
@Test(enabled = true, dataProvider = "GenotypesContextProvider")
public void testReplace(GenotypesContextProvider cfg) {
int n = cfg.makeContext().size();
for ( int i = 0; i < n; i++ ) {
GenotypesContext gc = cfg.makeContext();
Genotype toReplace = gc.get(i);
Genotype replacement = GenotypeBuilder.create(toReplace.getSampleName(), Arrays.asList(Aref, Aref));
gc.replace(replacement);
ArrayList<Genotype> l = new ArrayList<Genotype>(cfg.initialSamples);
l.set(i, replacement);
Assert.assertEquals(replacement, gc.get(i));
testGenotypesContextContainsExpectedSamples(gc, l);
}
}
// subset to samples tested in VariantContextUnitTest
}