/*
* The MIT License (MIT)
*
* Copyright (c) 2007-2015 by Institute for Computational Biomedicine,
* Weill Medical College of Cornell University.
*
* 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.goby;
import edu.cornell.med.icb.goby.alignments.AlignmentReader;
import edu.cornell.med.icb.goby.alignments.AlignmentReaderImpl;
import edu.cornell.med.icb.goby.alignments.Alignments;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import it.unimi.dsi.lang.MutableString;
import junit.framework.Assert;
import htsjdk.samtools.util.CloseableIterator;
import org.broad.igv.AbstractHeadlessTest;
import org.broad.igv.prefs.Constants;
import org.broad.igv.prefs.PreferencesManager;
import org.broad.igv.sam.Alignment;
import org.broad.igv.util.TestUtils;
import org.junit.Ignore;
import org.junit.Test;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Test Goby IGV classes.
* User: jrobinso
* Date: Jul 12, 2010
* Time: 11:25:52 AM
*/
public class GobyAlignmentQueryReaderTest extends AbstractHeadlessTest{
@Test
public void testGetSequenceNames() throws Exception {
Set<String> expectedSequences = new HashSet(Arrays.asList("GL000229.1", "GL000200.1", "GL000228.1", "GL000201.1", "GL000241.1", "GL000219.1",
"GL000191.1", "GL000242.1", "GL000243.1", "22", "GL000245.1", "MT", "3", "GL000217.1", "2", "1", "7", "6", "5",
"GL000215.1", "4", "9", "8", "GL000244.1", "GL000216.1", "GL000218.1", "GL000210.1", "GL000248.1", "GL000224.1",
"GL000203.1", "19", "17", "GL000194.1", "M", "18", "15", "16", "13", "14", "GL000195.1", "11", "12", "GL000225.1",
"21", "20", "GL000193.1", "GL000204.1", "GL000237.1", "GL000246.1", "Y", "GL000205.1", "GL000247.1", "X", "GL000192.1",
"GL000227.1", "GL000235.1", "GL000197.1", "GL000211.1", "GL000236.1", "GL000240.1", "GL000207.1", "GL000239.1", "GL000232.1",
"GL000212.1", "GL000238.1", "GL000231.1", "GL000233.1", "GL000226.1", "GL000249.1", "GL000223.1", "GL000199.1", "10", "GL000196.1",
"GL000209.1", "GL000202.1", "GL000214.1", "GL000220.1", "GL000198.1", "GL000208.1", "GL000221.1", "GL000213.1", "GL000234.1", "GL000222.1",
"GL000206.1", "GL000230.1"));
String thmFile = TestUtils.DATA_DIR + "goby/GDFQPGI-pickrellNA18486_yale.tmh";
GobyAlignmentQueryReader reader = new GobyAlignmentQueryReader(thmFile);
List<String> seqs = reader.getSequenceNames();
assertEquals(expectedSequences.size(), seqs.size());
for (String s : seqs) {
assertTrue(expectedSequences.contains(s));
}
}
@Test
public void testIterator() throws Exception {
String entriesFile = TestUtils.DATA_DIR + "goby/GDFQPGI-pickrellNA18486_yale.entries";
GobyAlignmentQueryReader reader = new GobyAlignmentQueryReader(entriesFile);
CloseableIterator<Alignment> iter = reader.iterator();
assertTrue(iter.hasNext());
iter.close();
reader.close();
}
/**
* Test a query interval that has alignments.
*
* @throws Exception
*/
@Test
public void testQueryPE() throws Exception {
String entriesFile = TestUtils.DATA_DIR + "goby/paired-end/paired-alignment.entries";
GobyAlignmentQueryReader.supportsFileType(entriesFile);
GobyAlignmentQueryReader reader = new GobyAlignmentQueryReader(entriesFile);
CloseableIterator<Alignment> iter = reader.query("chr1", 1, 240000000, false);
assertTrue(iter.hasNext());
iter.close();
reader.close();
}
/**
* Test a query interval with no alignments
*
* @throws Exception
*/
@Test
public void testQueryNoAlignments() throws Exception {
String entriesFile = TestUtils.DATA_DIR + "goby/paired-end/paired-alignment.entries";
GobyAlignmentQueryReader.supportsFileType(entriesFile);
GobyAlignmentQueryReader reader = new GobyAlignmentQueryReader(entriesFile);
CloseableIterator<Alignment> iter = reader.query("chr1", 1, 1000, false);
assertFalse(iter.hasNext());
iter.close();
reader.close();
}
/**
* Test a query interval with no alignments
*
* @throws Exception
*/
@Test
public void testHasNextBug() throws Exception {
String entriesFile = TestUtils.DATA_DIR + "goby/paired-end/paired-alignment.entries";
GobyAlignmentQueryReader.supportsFileType(entriesFile);
GobyAlignmentQueryReader reader = new GobyAlignmentQueryReader(entriesFile);
CloseableIterator<Alignment> iter = reader.iterator();
while (iter.hasNext()) {
Alignment alignment = iter.next();
assertNotNull(alignment);
}
}
/**
* Test a query interval with no alignments
*
* @throws Exception
*/
@Test
public void testOrdering() throws Exception {
String entriesFile = TestUtils.DATA_DIR + "goby/GDFQPGI-pickrellNA18486_yale.entries";
// String entriesFile = TestUtils.DATA_DIR + "goby/paired-end/paired-alignment.entries";
GobyAlignmentQueryReader.supportsFileType(entriesFile);
GobyAlignmentQueryReader reader = new GobyAlignmentQueryReader(entriesFile);
CloseableIterator<Alignment> iter = reader.iterator();
String previousChr = "";
int previousAlignmentStart = -1;
ObjectSet<String> chromosomeSeen = new ObjectArraySet<String>();
// maximum number of entries to inspect (keep low for faster test).
int maxEntries = 100000;
int countVisit = 0;
while (iter.hasNext()) {
Alignment a = iter.next();
final String entryChr = a.getChr();
// System.out.println("chr:" + entryChr);
if (entryChr.equals(previousChr)) {
assertTrue(a.getAlignmentStart() >= previousAlignmentStart);
} else {
assertFalse("Chromosomes should occur in blocks." +
" A chromosome that was used in a previous block of entry cannot occur again.",
chromosomeSeen.contains(a.getChr()));
previousChr = a.getChr();
chromosomeSeen.add(a.getChr());
}
countVisit++;
if (countVisit > maxEntries) break;
}
iter.close();
reader.close();
}
@Test
public void testAlignmentTwoMutations() {
Alignments.SequenceVariation mutation = Alignments.SequenceVariation.newBuilder().setFrom("AA").setTo("TC").
setPosition(10).setReadIndex(10).build();//.setToQuality(???).build();
Alignments.AlignmentEntry entry = Alignments.AlignmentEntry.newBuilder().
setQueryLength(50).setPosition(1000).setMatchingReverseStrand(false).
setQueryIndex(0).setTargetIndex(1).
setQueryAlignedLength(50).addSequenceVariations(mutation).build();
GobyAlignment gAlignment = new MockGobyAlignment(entry);
gAlignment.buildBlocks(entry);
assertEquals(1, gAlignment.block.length);
assertEquals(50, gAlignment.block[0].getBases().length);
}
@Test
public void testAlignmentLeftPadding() {
Alignments.AlignmentEntry entry = Alignments.AlignmentEntry.newBuilder().
setQueryLength(50).setPosition(1000).setMatchingReverseStrand(false).
setQueryIndex(0).setTargetIndex(1).
setQueryAlignedLength(30).setQueryPosition(20).build();
GobyAlignment
gAlignment = new MockGobyAlignment(entry);
gAlignment.buildBlocks(entry);
assertEquals(1, gAlignment.block.length);
assertEquals(30, gAlignment.block[0].getBases().length);
}
@Test
public void testAlignmentRightPadding() {
Alignments.AlignmentEntry entry = Alignments.AlignmentEntry.newBuilder().
setQueryLength(50).setPosition(1000).setMatchingReverseStrand(false).
setQueryIndex(0).setTargetIndex(1).
setQueryAlignedLength(30).setQueryPosition(0).build();
GobyAlignment
gAlignment = new MockGobyAlignment(entry);
gAlignment.buildBlocks(entry);
assertEquals(1, gAlignment.block.length);
assertEquals(30, gAlignment.block[0].getBases().length);
}
@Test
public void testAlignmentOneReadInsertion() {
Alignments.SequenceVariation mutation = Alignments.SequenceVariation.newBuilder().setFrom("--").setTo("TC").
setPosition(10).setReadIndex(10).build();
Alignments.AlignmentEntry entry = Alignments.AlignmentEntry.newBuilder().setPosition(1000).setMatchingReverseStrand(false).
setQueryLength(50).setQueryIndex(0).setTargetIndex(1).
setQueryAlignedLength(50).addSequenceVariations(mutation).build();
GobyAlignment
gAlignment = new MockGobyAlignment(entry);
gAlignment.buildBlocks(entry);
assertEquals(1, gAlignment.block.length);
assertEquals(1, gAlignment.insertionBlock.length);
assertEquals(1010, gAlignment.insertionBlock[0].getStart());
// the aligned block is 50-2 because the 2 bases are in their own insertion block.
assertEquals(48, gAlignment.block[0].getBases().length);
}
@Test
public void testAlignmentOneReadDeletion() {
Alignments.SequenceVariation mutation = Alignments.SequenceVariation.newBuilder().setFrom("TC").setTo("--").
setPosition(10).setReadIndex(10).build();
Alignments.AlignmentEntry entry = Alignments.AlignmentEntry.newBuilder().setPosition(1000).setMatchingReverseStrand(false).
setQueryLength(50).setQueryIndex(0).setTargetIndex(1).
setQueryAlignedLength(50).addSequenceVariations(mutation).build();
GobyAlignment
gAlignment = new MockGobyAlignment(entry);
gAlignment.buildBlocks(entry);
assertEquals(2, gAlignment.block.length);
assertEquals(9, gAlignment.block[0].getBases().length);
assertEquals(41, gAlignment.block[1].getBases().length);
}
@Test
public void testAlignmentActualEntry1() {
/**
* query_index: 26
target_index: 0
position: 31
score: 43.0
query_position: 1
matching_reverse_strand: true
multiplicity: 1
number_of_mismatches: 2
number_of_indels: 3
query_length: 50
query_aligned_length: 48
target_aligned_length: 45
sequence_variations {
to: "AA"
from: "CC"
position: 10
read_index: 40
}
sequence_variations {
to: "ATC"
from: "---"
position: 25
read_index: 24
}
Alignment start position = chrsynth1:32
read-sequence
*/
Alignments.SequenceVariation mutation1 = Alignments.SequenceVariation.newBuilder().setFrom("ATC").setTo("---").
setPosition(25).setReadIndex(24).build();
Alignments.SequenceVariation mutation2 = Alignments.SequenceVariation.newBuilder().setFrom("AA").setTo("CC").
setPosition(10).setReadIndex(40).build();
Alignments.AlignmentEntry entry = Alignments.AlignmentEntry.newBuilder().setPosition(31).setMatchingReverseStrand(true).
setQueryLength(50).setQueryIndex(26).setTargetIndex(1).
setQueryAlignedLength(40).setNumberOfMismatches(2).setNumberOfIndels(3).addSequenceVariations(mutation1).
addSequenceVariations(mutation2).build();
GobyAlignment
gAlignment = new MockGobyAlignment(entry);
gAlignment.buildBlocks(entry);
assertEquals(2, gAlignment.block.length);
assertEquals(24, gAlignment.block[0].getBases().length);
assertEquals(16, gAlignment.block[1].getBases().length);
}
@Test
public void testAlignmentWithSplicing() throws IOException {
Alignments.SequenceVariation mutation = Alignments.SequenceVariation.newBuilder().setFrom("T").setTo("A").
setPosition(10).setReadIndex(10).build();
Alignments.RelatedAlignmentEntry linkForward = Alignments.RelatedAlignmentEntry.newBuilder().
setFragmentIndex(1).setPosition(1200).setTargetIndex(1).build();
Alignments.RelatedAlignmentEntry linkBackward = Alignments.RelatedAlignmentEntry.newBuilder().
setFragmentIndex(0).setPosition(1000).setTargetIndex(1).build();
Alignments.AlignmentEntry entry1 = Alignments.AlignmentEntry.newBuilder().setPosition(1000).setMatchingReverseStrand(false).
setQueryLength(50).setQueryIndex(0).setTargetIndex(1).setFragmentIndex(0).setSplicedForwardAlignmentLink(linkForward).
setQueryAlignedLength(20).addSequenceVariations(mutation).build();
Alignments.AlignmentEntry entry2 = Alignments.AlignmentEntry.newBuilder().setPosition(1200).setMatchingReverseStrand(false).
setQueryLength(50).setQueryIndex(0).setTargetIndex(1).setFragmentIndex(1).setSplicedBackwardAlignmentLink(linkBackward).
setQueryAlignedLength(30).build();
ObjectArrayList<Alignments.AlignmentEntry> alignments = new ObjectArrayList<Alignments.AlignmentEntry>();
alignments.add(entry1);
alignments.add(entry2);
final ObjectListIterator<Alignments.AlignmentEntry> iterator = alignments.iterator();
GobyAlignmentIterator alignIterator = new GobyAlignmentIterator(1, 0, 10000) {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Alignment next() {
return new GobyAlignment(this, iterator.next());
}
@Override
public MutableString getId(int targetIndex){
return new MutableString("chrMock");
}
};
ObjectArrayList<GobyAlignment> visitedEntries = new ObjectArrayList<GobyAlignment>();
while (alignIterator.hasNext()) {
GobyAlignment align = (GobyAlignment) alignIterator.next();
visitedEntries.add(align);
}
int index = 0;
for (GobyAlignment align : visitedEntries) {
if (index == 0) {
assertEquals(2, align.block.length);
assertEquals(20, align.block[0].getBases().length);
assertEquals(30, align.block[1].getBases().length);
}
if (index == 1) {
assertEquals(0, align.block.length);
}
index++;
}
}
@Test
public void testTricky1() throws IOException {
String entriesFile = TestUtils.DATA_DIR + "goby/tricky/sorted-tricky-spliced-17.header";
GobyAlignmentQueryReader reader = new GobyAlignmentQueryReader(entriesFile);
CloseableIterator<Alignment> iter = reader.iterator();
assertTrue(iter.hasNext());
Alignment igvAlignment = iter.next();
boolean showSoftClipped = PreferencesManager.getPreferences().getAsBoolean(Constants.SAM_SHOW_SOFT_CLIPPED);
Assert.assertEquals(2 + (showSoftClipped ? 1 : 0), igvAlignment.getAlignmentBlocks().length);
Assert.assertEquals("==A====G===GA=====T============================================",
basesToText(igvAlignment.getAlignmentBlocks()[1 + (showSoftClipped ? 1 : 0)].getBases()));
iter.close();
reader.close();
}
@Test
public void testOldGobyHybrid() throws IOException {
AlignmentReader reader = new AlignmentReaderImpl(TestUtils.DATA_DIR + "goby/GDFQPGI-pickrellNA18486_yale-hybrid.entries");
org.junit.Assert.assertTrue(reader.hasNext());
}
// Test below is disabled, it depends on a resource we don't control
@Ignore
public void testOldGobyHybridUrl() throws IOException {
AlignmentReader reader = new AlignmentReaderImpl("http://gobyweb.apps.campagnelab.org/data/H_T_D/MYHZZJH/MYHZZJH-hybrid-domain.header");
reader.reposition(10, 1210);
final Alignments.AlignmentEntry entry = reader.skipTo(10, 1210);
org.junit.Assert.assertNotNull(entry);
}
private String basesToText(byte[] bases) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bases.length; i++) {
sb.append((char) bases[i]);
}
return sb.toString();
}
private static class MockGobyAlignment extends GobyAlignment{
@Override
public String getChr() {
return "chrMock";
}
MockGobyAlignment(final Alignments.AlignmentEntry entry){
super(null, entry);
}
}
}