/*
* 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.sam;
import htsjdk.samtools.*;
import org.broad.igv.AbstractHeadlessTest;
import org.broad.igv.sam.reader.AlignmentReader;
import org.broad.igv.sam.reader.AlignmentReaderFactory;
import org.broad.igv.sam.reader.MergedAlignmentReaderTest;
import org.broad.igv.sam.reader.SAMReader;
import org.broad.igv.util.ResourceLocator;
import org.broad.igv.util.TestUtils;
import org.junit.Test;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
/**
* User: jacob
* Date: 2012/05/04
*/
public class SAMWriterTest extends AbstractHeadlessTest {
final static String ifile = TestUtils.DATA_DIR + "/sam/NA12878.muc1.test.sam";
@Test
public void testWriteRecordsFile() throws Exception {
testWriteRecords(ifile, false);
}
@Test
public void testWriteRecordsStream() throws Exception {
testWriteRecords(ifile, true);
}
/**
* Check that the alignments read from {@code outFile} are the same as those in {@code origAlignments}
*
* @param origAlignments
* @param outFile
* @param origPath Used for error message only. Can be null
* @throws java.io.IOException
*/
public void checkRecordsMatch(List<PicardAlignment> origAlignments, File outFile, String origPath) throws IOException {
//Read back in, check equality
AlignmentReader outputReader = AlignmentReaderFactory.getReader(outFile.getAbsolutePath(), false);
Iterator<Alignment> outputIter = outputReader.iterator();
int index = 0;
while (outputIter.hasNext()) {
Alignment outputAl = outputIter.next();
Alignment origAl = origAlignments.get(index);
String errmsg = "Cigar strings not equal at " + index + " in " + origAl.getReadName();
if (origPath != null) {
errmsg += " in file " + origPath;
}
assertEquals(errmsg, origAl.getCigarString(), outputAl.getCigarString());
index++;
}
assertEquals("Incorrect number of alignments", origAlignments.size(), index);
}
/**
* Test our ability to write SAM Records out.
* We check both bam and sam output format
* <p>
* If outStream is true, we use the stream writing methods of SAMWriter,
* otherwise, file writing methods
*
* @throws Exception
*/
public void testWriteRecords(String inpath, boolean outStream) throws Exception {
String[] outpaths = new String[]{TestUtils.DATA_DIR + "out/tmp_sam.sam", TestUtils.DATA_DIR + "out/tmp_bam.bam"};
for (String outpath : outpaths) {
SamHeaderIterator shi = new SamHeaderIterator(inpath);
File outFile = new File(outpath);
outFile.delete();
outFile.deleteOnExit();
SAMWriter writer = new SAMWriter(shi.header);
boolean bam = outpath.endsWith(".bam");
if (!outStream) {
writer.writeToFile(outFile, shi.alignments.iterator(), false);
} else {
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outFile));
writer.writeToStream(outputStream, shi.alignments.iterator(), bam);
}
checkRecordsMatch(shi.alignments, outFile, inpath);
}
}
private static class SamHeaderIterator {
private SAMFileHeader header;
private List<PicardAlignment> alignments;
public SamHeaderIterator(String inpath) throws IOException {
SAMReader reader = new SAMReader(inpath, false);
this.header = reader.getFileHeader();
Iterator<PicardAlignment> iter = reader.iterator();
alignments = new ArrayList<PicardAlignment>();
while (iter.hasNext()) {
alignments.add(iter.next());
}
}
}
@Test
public void testCopyBAMFile_01() throws Exception {
String sequence = "chr1";
int end = 300000000;
int start = end / 5 - 1;
String inpath = TestUtils.LARGE_DATA_DIR + "HG00171.hg18.bam";
ResourceLocator inlocator = new ResourceLocator(inpath);
tstCopyBAMFile(inlocator, sequence, start, end);
}
@Test
public void testCopyMergedBAM_01() throws Exception {
String sequence = "chr1";
int start = 151667156;
int end = start + 10000;
File listFile = new File(TestUtils.LARGE_DATA_DIR, "2largebams.bam.list");
MergedAlignmentReaderTest.generateRepLargebamsList(listFile);
ResourceLocator inlocator = new ResourceLocator(listFile.getAbsolutePath());
tstCopyBAMFile(inlocator, sequence, start, end);
}
public void tstCopyBAMFile(ResourceLocator inlocator, String sequence, int start, int end) throws IOException {
boolean createIndex = true;
String outPath = TestUtils.TMP_OUTPUT_DIR + "tmpbam.bam";
File outFile = new File(outPath);
File indexFile = new File(outPath.replace(".bam", ".bai"));
outFile.delete();
indexFile.delete();
outFile.deleteOnExit();
indexFile.deleteOnExit();
int writtenCount = SAMWriter.writeAlignmentFilePicard(inlocator, outPath, sequence, start, end);
assertEquals("Index file existence unexpected: " + indexFile.getAbsolutePath(), createIndex, indexFile.exists());
SamInputResource resource = SamInputResource.of(outPath);
SamReader writtenReader = SamReaderFactory.makeDefault().
validationStringency(ValidationStringency.SILENT).open(resource);
SAMRecordIterator iter = null;
if (createIndex) {
iter = writtenReader.queryOverlapping(sequence, start + 1, end);
} else {
iter = writtenReader.iterator();
}
int readCount = 0;
while (iter.hasNext()) {
readCount++;
iter.next();
}
System.out.println(readCount + " alignments read");
assertTrue("No alignments read", readCount > 0);
assertEquals("Read a different number of alignments than written", writtenCount, readCount);
}
}