/*
* The MIT License (MIT)
*
* Copyright (c) 2007-2015 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 org.broad.igv.tools;
import org.broad.igv.AbstractHeadlessTest;
import org.broad.igv.prefs.IGVPreferences;
import org.broad.igv.feature.genome.Genome;
import org.broad.igv.prefs.PreferencesManager;
import org.broad.igv.tools.parsers.DataConsumer;
import org.broad.igv.track.TrackType;
import org.broad.igv.util.TestUtils;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import static junit.framework.Assert.assertEquals;
public class CoverageCounterTest extends AbstractHeadlessTest {
static IGVPreferences preferenceManager;
@BeforeClass
public static void setUpClass() throws Exception {
AbstractHeadlessTest.setUpClass();
preferenceManager = PreferencesManager.getPreferences();
}
/**
* Test the "mapping quality" flag. Also indirectly tests the query parameters.
*/
@Test
public void testMappingQualityFlag() throws IOException {
String bamURL = TestUtils.LARGE_DATA_DIR + "HG00171.hg18.bam";
String queryString = "chr1:152522155-152522155";
int minMapQuality = 40;
File wigFile = new File(TestUtils.DATA_DIR + "out/testMapQual.wig");
int windowSize = 1;
TestDataConsumer dc = new TestDataConsumer();
CoverageCounter cc = new CoverageCounter(bamURL, dc, windowSize, 0, wigFile, genome, queryString, minMapQuality, 0);
cc.parse();
String totalCount = dc.attributes.get("totalCount");
assertEquals("7", totalCount);
}
@Ignore // The test file no longer exists
@Test
public void testPairFlag() throws Exception{
String bamURL = "http://data.broadinstitute.org/igvdata/1KG/pilot2Bams/NA12878.SLX.bam";
String queryString = "2:1000-1100";
File wigFile = new File(TestUtils.DATA_DIR + "out/testPair.wig");
int windowSize = 1;
TestDataConsumer dc = new TestDataConsumer();
CoverageCounter cc = new CoverageCounter(bamURL, dc, windowSize, 0, wigFile, genome, queryString, 0, CoverageCounter.PAIRED_COVERAGE);
cc.parse();
//Have manually checked these regions and verified that there is 1 pair
//in the 1000-1100 region, and 4 at location 851
//with
for(TestData td: dc.testDatas){
assertEquals(1.0f, td.data[0]);
}
queryString = "2:851";
dc = new TestDataConsumer();
cc = new CoverageCounter(bamURL, dc, windowSize, 0, wigFile, genome, queryString, 0, CoverageCounter.PAIRED_COVERAGE);
cc.parse();
for(TestData td: dc.testDatas){
assertEquals(4.0f, td.data[0]);
}
}
/*
Test whether we count the number of features correctly.
*/
@Test
public void testCountStrand() throws Exception {
String ifile = TestUtils.DATA_DIR + "bed/Unigene.sample.sorted.bed";
int expTot = 71;
int windowSize = 25;
File wigFile = null;
int[] countFlags = new int[]{0, CoverageCounter.STRANDS_BY_READ, CoverageCounter.STRANDS_BY_FIRST_IN_PAIR,
CoverageCounter.BASES,
CoverageCounter.INCLUDE_DUPS, CoverageCounter.BASES + CoverageCounter.STRANDS_BY_READ,
CoverageCounter.BASES + CoverageCounter.STRANDS_BY_FIRST_IN_PAIR};
//We specifically do not test this, because it's unreliable. Some alignments default to assuming they
//are the first in pair, but let secondinpair be none
//countFlags = new int[]{CoverageCounter.STRANDS_BY_SECOND_IN_PAIR};
int[] expectedTotal = new int[]{expTot, expTot, expTot, expTot, expTot, expTot, expTot, expTot};
for (int ii = 0; ii < countFlags.length; ii++) {
TestDataConsumer dc = new TestDataConsumer();
CoverageCounter cc = new CoverageCounter(ifile, dc, windowSize, 0, wigFile, genome, null, 0, countFlags[ii]);
cc.parse();
String totalCount = dc.attributes.get("totalCount");
int totCount = Integer.valueOf(totalCount);
assertEquals(expectedTotal[ii], totCount);
}
}
@Test
public void testCountBases() throws Exception {
String ifile = TestUtils.DATA_DIR + "sam/NA12878.muc1.test.sam";
int expected_cols = 14;
File wigFile = new File(TestUtils.DATA_DIR + "out", "testCountBases.wig");
int windowSize = 1;
TestDataConsumer dc = new TestDataConsumer();
int strandOptions = CoverageCounter.STRANDS_BY_READ + CoverageCounter.BASES;
CoverageCounter cc = new CoverageCounter(ifile, dc, windowSize, 0, wigFile, genome, null, 0, strandOptions);
cc.parse();
int check_startpos = 153426135 - 1;
Map<Byte, Integer> posCounts = new HashMap<Byte, Integer>();
Map<Byte, Integer> negCounts = new HashMap<Byte, Integer>();
byte[] keys = new byte[]{'A', 'C', 'G', 'T', 'N', CoverageCounter.DEL, CoverageCounter.INS};
int[] posvals = new int[]{9, 0, 0, 2, 0, 0, 0};
int[] negvals = new int[]{16, 0, 0, 0, 0, 0, 0};
for (int ii = 0; ii < keys.length; ii++) {
posCounts.put(keys[ii], posvals[ii]);
negCounts.put(keys[ii], negvals[ii]);
}
for (TestData tdata : dc.testDatas) {
float[] numbers = tdata.data;
assertEquals(expected_cols, numbers.length);
if (tdata.start == check_startpos) {
for (int ii = 0; ii < posvals.length; ii++) {
assertEquals(posvals[ii], numbers[ii], 1e-2);
assertEquals(negvals[ii], numbers[ii + keys.length], 1e-2);
}
}
}
}
/**
* Test different strand options, just count output columns
* and make sure we get the right number
*
* @throws Exception
*/
public void testColumnCounts() throws Exception {
String ifile = TestUtils.DATA_DIR + "sam/NA12878.muc1.test.sam";
File wigFile = null;
Genome genome = this.genome;
int[] windowSizes = new int[]{1, 50, 100, 500};
//All possible combinations of STRAND_XXX flags
int[] strandops = new int[2];
strandops[0] = 0;
strandops[1] = CoverageCounter.STRANDS_BY_READ;
// String[] otherflags = new String[]{CoverageCounter.FIRST_IN_PAIR, CoverageCounter.BASES,
// CoverageCounter.FIRST_IN_PAIR + CoverageCounter.BASES};
// for (String so : strandops) {
// for (String of : otherflags) {
// int expectedcols = so.contains(CoverageCounter.STRAND_SEPARATE) ? 2 : 1;
// if (of.contains(CoverageCounter.BASES)) {
// expectedcols *= 5;
// }
//
// String strandOptions = so + of;
// for (int windowSize : windowSizes) {
// TestDataConsumer dc = new TestDataConsumer();
// CoverageCounter cc = new CoverageCounter(ifile, dc, windowSize, 0, wigFile, genome, "sc=" + strandOptions);
// cc.parse();
//
// assertEquals(expectedcols, dc.testDatas.get(0).data.length);
// }
// }
// }
}
@Test
public void testIncludeDuplicatesFlag() throws IOException {
String bamURL = "http://data.broadinstitute.org/igvdata/BodyMap/hg18/Merged/HBM.adipose.bam.sorted.bam";
int options = CoverageCounter.INCLUDE_DUPS;
String queryString = "chr1:153425249-153425249";
int windowSize = 1;
File wigFile = null;
Genome genome = null;
TestDataConsumer dc = new TestDataConsumer();
CoverageCounter cc = new CoverageCounter(bamURL, dc, windowSize, 0, wigFile, genome, queryString, 0, options);
cc.parse();
String totalCount = dc.attributes.get("totalCount");
assertEquals("22", totalCount);
}
static class TestDataConsumer implements DataConsumer {
Map<String, String> attributes = new HashMap<String, String>();
public ArrayList<TestData> testDatas = new ArrayList<TestData>();
public void setType(String type) {
}
/**
* Just write all the data a containment object
*
* @param chr
* @param start
* @param end
* @param data
* @param name
*/
public void addData(String chr, int start, int end, float[] data, String name) {
TestData newData = new TestData(chr, start, end, data.clone(), name);
this.testDatas.add(newData);
}
public void parsingComplete() {
}
public void setTrackParameters(TrackType trackType, String trackLine, String[] trackNames) {
}
public void setTrackParameters(TrackType trackType, String trackLine, String[] trackNames, boolean b) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void setSortTolerance(int tolerance) {
}
public void setAttribute(String key, String value) {
attributes.put(key, value);
}
}
private static class TestData {
public String chr;
public int start;
public int end;
public float[] data;
public String name;
public TestData(String chr, int start, int end, float[] data, String name) {
this.chr = chr;
this.start = start;
this.end = end;
this.data = data;
this.name = name;
}
}
}