org.dishevelled.bio.alignment.sam.SamReaderTest.java Source code

Java tutorial

Introduction

Here is the source code for org.dishevelled.bio.alignment.sam.SamReaderTest.java

Source

/*
    
dsh-bio-alignment  Aligments.
Copyright (c) 2013-2019 held jointly by the individual authors.
    
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or (at
your option) any later version.
    
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
License for more details.
    
You should have received a copy of the GNU Lesser General Public License
along with this library;  if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
    
> http://www.fsf.org/licensing/licenses/lgpl.html
> http://www.opensource.org/licenses/lgpl-license.php
    
*/
package org.dishevelled.bio.alignment.sam;

import static org.dishevelled.bio.alignment.sam.SamReader.header;
import static org.dishevelled.bio.alignment.sam.SamReader.parse;
import static org.dishevelled.bio.alignment.sam.SamReader.stream;
import static org.dishevelled.bio.alignment.sam.SamReader.records;

import static org.apache.commons.codec.binary.Hex.decodeHex;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.IOException;
import java.io.PrintWriter;

import java.net.URL;

import java.nio.CharBuffer;

import java.util.Arrays;
import java.util.Iterator;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;

import com.google.common.io.Files;
import com.google.common.io.Resources;

import com.google.common.primitives.Bytes;

import org.junit.Before;
import org.junit.Test;

/**
 * Unit test for SamReader.
 *
 * @author  Michael Heuer
 */
public final class SamReaderTest {
    private Readable readable;
    private Readable emptyReadable;
    private SamParseListener parseListener;
    private SamStreamListener streamListener;
    private static final String SAM = "NA12878-platinum-chr20.1-60250.sam";

    @Before
    public void setUp() {
        readable = CharBuffer.wrap("@HD\tVN:1.5\tSO:coordinate");
        emptyReadable = CharBuffer.wrap("");
        parseListener = new SamParseAdapter();
        streamListener = new SamStreamAdapter();
    }

    @Test(expected = NullPointerException.class)
    public void testParseNullReadable() throws Exception {
        parse(null, parseListener);
    }

    @Test(expected = NullPointerException.class)
    public void testParseNullParseListener() throws Exception {
        parse(readable, null);
    }

    @Test
    public void testParse() throws Exception {
        parse(readable, parseListener);
    }

    @Test(expected = NullPointerException.class)
    public void testStreamNullReadable() throws Exception {
        stream(null, streamListener);
    }

    @Test(expected = NullPointerException.class)
    public void testStreamNullStreamListener() throws Exception {
        stream(readable, null);
    }

    @Test
    public void testStream() throws Exception {
        stream(readable, streamListener);
    }

    @Test
    public void testStreamFile() throws Exception {
        try (BufferedReader reader = new BufferedReader(new FileReader(createFile(SAM)))) {
            stream(reader, new SamStreamAdapter() {
                @Override
                public void record(final SamRecord record) {
                    validateRecord(record);
                }
            });
        }
    }

    @Test(expected = NullPointerException.class)
    public void testHeaderNullReadable() throws Exception {
        header((Readable) null);
    }

    @Test
    public void testHeaderEmptyReadable() throws Exception {
        SamHeader header = header(emptyReadable);
        assertFalse(header.getHeaderLineOpt().isPresent());
        assertTrue(header.getSequenceHeaderLines().isEmpty());
        assertTrue(header.getReadGroupHeaderLines().isEmpty());
        assertTrue(header.getProgramHeaderLines().isEmpty());
        assertTrue(header.getCommentHeaderLines().isEmpty());
    }

    @Test
    public void testHeader() throws Exception {
        SamHeader header = header(readable);
        assertTrue(header.getHeaderLineOpt().isPresent());
        SamHeaderLine headerLine = header.getHeaderLineOpt().get();
        assertEquals("1.5", headerLine.getVn());
        assertEquals("1.5", headerLine.getField("VN"));
        assertTrue(headerLine.getFieldOpt("VN").isPresent());
        assertEquals("1.5", headerLine.getFieldOpt("VN").get());
        assertEquals("1.5", headerLine.getFields().get("VN"));
        assertEquals("coordinate", headerLine.getSo());
        assertEquals("coordinate", headerLine.getFields().get("SO"));
        assertFalse(headerLine.containsGo());
        assertFalse(headerLine.getFields().containsKey("GO"));
        assertTrue(header.getSequenceHeaderLines().isEmpty());
        assertTrue(header.getReadGroupHeaderLines().isEmpty());
        assertTrue(header.getProgramHeaderLines().isEmpty());
        assertTrue(header.getCommentHeaderLines().isEmpty());
    }

    @Test(expected = NullPointerException.class)
    public void testHeadeNullFile() throws Exception {
        header((File) null);
    }

    @Test
    public void testHeaderFile() throws Exception {
        validateHeader(header(createFile(SAM)));
    }

    @Test(expected = NullPointerException.class)
    public void testHeaderNullUrl() throws Exception {
        header((URL) null);
    }

    @Test
    public void testHeaderUrl() throws Exception {
        validateHeader(header(createUrl(SAM)));
    }

    @Test(expected = NullPointerException.class)
    public void testHeaderNullInputStream() throws Exception {
        header((InputStream) null);
    }

    @Test
    public void testHeaderInputStream() throws Exception {
        validateHeader(header(createInputStream(SAM)));
    }

    @Test(expected = NullPointerException.class)
    public void testRecordsNullReadable() throws Exception {
        records((Readable) null);
    }

    @Test
    public void testRecordsEmptyReadable() throws Exception {
        records(emptyReadable);
    }

    @Test
    public void testRecords() throws Exception {
        Iterable<SamRecord> records = records(readable);
        assertNotNull(records);
        assertTrue(ImmutableList.copyOf(records).isEmpty());
    }

    @Test(expected = NullPointerException.class)
    public void testRecordsNullFile() throws Exception {
        records((File) null);
    }

    @Test
    public void testRecordsFile() throws Exception {
        validateRecords(records(createFile(SAM)));
    }

    @Test(expected = NullPointerException.class)
    public void testRecordsNullUrl() throws Exception {
        records((URL) null);
    }

    @Test
    public void testRecordsUrl() throws Exception {
        validateRecords(records(createUrl(SAM)));
    }

    @Test(expected = NullPointerException.class)
    public void testRecordsNullInputStream() throws Exception {
        records((InputStream) null);
    }

    @Test
    public void testRecordsInputStream() throws Exception {
        validateRecords(records(createInputStream(SAM)));
    }

    @Test
    public void testRecordsTags() throws Exception {
        for (SamRecord record : records(createInputStream("tags.sam"))) {
            if ("StandardTags".equals(record.getQname())) {
                // NM:i:0  MD:Z:10  XS:A:-
                assertEquals(0, record.getFieldInteger("NM"));
                assertEquals("10", record.getFieldString("MD"));
                assertEquals('-', record.getFieldCharacter("XS"));
                assertEquals("i", record.getFieldTypes().get("NM"));
                assertEquals("Z", record.getFieldTypes().get("MD"));
                assertEquals("A", record.getFieldTypes().get("XS"));
            } else if ("MDTagWithEdits".equals(record.getQname())) {
                // NM:i:2  MD:Z:3G4T1
                assertEquals(2, record.getFieldInteger("NM"));
                assertEquals("3G4T1", record.getFieldString("MD"));
                assertEquals("i", record.getFieldTypes().get("NM"));
                assertEquals("Z", record.getFieldTypes().get("MD"));
            } else if ("HexByteArray".equals(record.getQname())) {
                // NM:i:0  MD:Z:10  XB:H:010203
                assertEquals(0, record.getFieldInteger("NM"));
                assertEquals("10", record.getFieldString("MD"));
                assertEquals("010203", record.getFieldString("XB"));
                assertTrue(Arrays.equals(decodeHex("010203"), record.getFieldByteArray("XB")));
                assertEquals(Bytes.asList(decodeHex("010203")), record.getFieldBytes("XB"));
                assertEquals("i", record.getFieldTypes().get("NM"));
                assertEquals("Z", record.getFieldTypes().get("MD"));
                assertEquals("H", record.getFieldTypes().get("XB"));
            } else if ("LengthOneArrays".equals(record.getQname())) {
                // NM:i:0  MD:Z:10  XB:B:c,1  XI:B:i,1  XS:B:s,1  XF:B:f,1
                assertEquals(0, record.getFieldInteger("NM"));
                assertEquals("10", record.getFieldString("MD"));
                assertEquals(ImmutableList.of(1), record.getFieldIntegers("XB"));
                assertEquals(ImmutableList.of(1), record.getFieldIntegers("XI"));
                assertEquals(ImmutableList.of(1), record.getFieldIntegers("XS"));
                assertEquals(ImmutableList.of(1.0f), record.getFieldFloats("XF"));
                assertEquals("B", record.getFieldTypes().get("XB"));
                assertEquals("c", record.getFieldArrayTypes().get("XB"));
                assertEquals("B", record.getFieldTypes().get("XI"));
                assertEquals("i", record.getFieldArrayTypes().get("XI"));
                assertEquals("B", record.getFieldTypes().get("XS"));
                assertEquals("s", record.getFieldArrayTypes().get("XS"));
                assertEquals("B", record.getFieldTypes().get("XF"));
                assertEquals("f", record.getFieldArrayTypes().get("XF"));
            } else if ("LongerArrays".equals(record.getQname())) {
                // NM:i:0  MD:Z:10  XB:B:c,1,2,3  XI:B:i,1,2,3  XS:B:s,1,2,3  XS:B:f,1,2,3
                assertEquals(0, record.getFieldInteger("NM"));
                assertEquals("10", record.getFieldString("MD"));
                assertEquals(ImmutableList.of(1, 2, 3), record.getFieldIntegers("XB"));
                assertEquals(ImmutableList.of(1, 2, 3), record.getFieldIntegers("XI"));
                assertEquals(ImmutableList.of(1, 2, 3), record.getFieldIntegers("XS"));
                assertEquals(ImmutableList.of(1.0f, 2.0f, 3.0f), record.getFieldFloats("XF"));
                assertEquals("B", record.getFieldTypes().get("XB"));
                assertEquals("c", record.getFieldArrayTypes().get("XB"));
                assertEquals("B", record.getFieldTypes().get("XI"));
                assertEquals("i", record.getFieldArrayTypes().get("XI"));
                assertEquals("B", record.getFieldTypes().get("XS"));
                assertEquals("s", record.getFieldArrayTypes().get("XS"));
                assertEquals("B", record.getFieldTypes().get("XF"));
                assertEquals("f", record.getFieldArrayTypes().get("XF"));
            } else if ("SignedArrays".equals(record.getQname())) {
                // NM:i:0  MD:Z:10  XB:B:c,-1  XI:B:i,-1  XS:B:s,-1
                assertEquals(0, record.getFieldInteger("NM"));
                assertEquals("10", record.getFieldString("MD"));
                assertEquals(ImmutableList.of(-1), record.getFieldIntegers("XB"));
                assertEquals(ImmutableList.of(-1), record.getFieldIntegers("XI"));
                assertEquals(ImmutableList.of(-1), record.getFieldIntegers("XS"));
                assertEquals("B", record.getFieldTypes().get("XB"));
                assertEquals("c", record.getFieldArrayTypes().get("XB"));
                assertEquals("B", record.getFieldTypes().get("XI"));
                assertEquals("i", record.getFieldArrayTypes().get("XI"));
                assertEquals("B", record.getFieldTypes().get("XS"));
                assertEquals("s", record.getFieldArrayTypes().get("XS"));
            } else if ("UnsignedArrays".equals(record.getQname())) {
                // NM:i:0  MD:Z:10  XB:B:C,1,2,3  XI:B:I,1,2,3  XS:B:S,1,2,3
                assertEquals(0, record.getFieldInteger("NM"));
                assertEquals("10", record.getFieldString("MD"));
                assertEquals(ImmutableList.of(1, 2, 3), record.getFieldIntegers("XB"));
                assertEquals(ImmutableList.of(1, 2, 3), record.getFieldIntegers("XI"));
                assertEquals(ImmutableList.of(1, 2, 3), record.getFieldIntegers("XS"));
                assertEquals("B", record.getFieldTypes().get("XB"));
                assertEquals("C", record.getFieldArrayTypes().get("XB"));
                assertEquals("B", record.getFieldTypes().get("XI"));
                assertEquals("I", record.getFieldArrayTypes().get("XI"));
                assertEquals("B", record.getFieldTypes().get("XS"));
                assertEquals("S", record.getFieldArrayTypes().get("XS"));
            }
        }
    }

    @Test
    public void testRoundTripDefaults() throws Exception {
        SamRecord expected = SamRecord.builder().build();

        File tmp = File.createTempFile("samReaderTest", ".sam");
        tmp.deleteOnExit();
        try (PrintWriter writer = new PrintWriter(new FileWriter(tmp))) {
            SamWriter.writeRecord(expected, writer);
        }
        SamRecord observed = records(tmp).iterator().next();

        assertEquals(expected.getQname(), observed.getQname());
        assertEquals(expected.getFlag(), observed.getFlag());
        assertEquals(expected.getRname(), observed.getRname());
        assertEquals(expected.getPos(), observed.getPos());
        assertEquals(expected.getMapq(), observed.getMapq());
        assertEquals(expected.getCigar(), observed.getCigar());
        assertEquals(expected.getRnext(), observed.getRnext());
        assertEquals(expected.getPnext(), observed.getPnext());
        assertEquals(expected.getTlen(), observed.getTlen());
        assertEquals(expected.getSeq(), observed.getSeq());
        assertEquals(expected.getQual(), observed.getQual());
        assertEquals(expected.getFields(), observed.getFields());
        assertEquals(expected.getFieldTypes(), observed.getFieldTypes());
        assertEquals(expected.getFieldArrayTypes(), observed.getFieldArrayTypes());
    }

    @Test
    public void testRoundTripOptionalFields() throws Exception {
        SamRecord expected = SamRecord.builder().withField("ZA", "A", "c").withField("ZI", "i", "42")
                .withField("ZF", "f", "3.14").withField("ZH", "H", "010203").withField("ZZ", "Z", "hello world!")
                .withArrayField("ZB", "B", "i", "1", "2").withArrayField("ZT", "B", "f", "3.4", "4.5").build();

        File tmp = File.createTempFile("samReaderTest", ".sam");
        tmp.deleteOnExit();
        try (PrintWriter writer = new PrintWriter(new FileWriter(tmp))) {
            SamWriter.writeRecord(expected, writer);
        }
        SamRecord observed = records(tmp).iterator().next();

        assertEquals(expected.getFieldCharacter("ZA"), observed.getFieldCharacter("ZA"));
        assertEquals(expected.getFieldInteger("ZI"), observed.getFieldInteger("ZI"));
        assertEquals(expected.getFieldFloat("ZF"), observed.getFieldFloat("ZF"), 0.1f);
        assertTrue(Arrays.equals(expected.getFieldByteArray("ZH"), observed.getFieldByteArray("ZH")));
        assertEquals(expected.getFieldString("ZZ"), observed.getFieldString("ZZ"));
        assertEquals(expected.getFieldIntegers("ZB"), observed.getFieldIntegers("ZB"));
        assertEquals(expected.getFieldFloats("ZT"), observed.getFieldFloats("ZT"));
    }

    @Test
    public void testRoundTripWholeFile() throws Exception {
        SamHeader expectedHeader = header(createFile(SAM));
        Iterable<SamRecord> expectedRecords = records(createFile(SAM));
        SamRecord expectedRecord = expectedRecords.iterator().next();

        File tmp = File.createTempFile("samReaderTest", ".sam");
        tmp.deleteOnExit();
        try (PrintWriter writer = new PrintWriter(new FileWriter(tmp))) {
            SamWriter.write(expectedHeader, expectedRecords, writer);
        }

        SamHeader observedHeader = header(tmp);
        assertTrue(observedHeader.getHeaderLineOpt().isPresent());
        assertEquals(expectedHeader.getSequenceHeaderLines().size(),
                observedHeader.getSequenceHeaderLines().size());
        assertEquals(expectedHeader.getReadGroupHeaderLines().size(),
                observedHeader.getReadGroupHeaderLines().size());
        assertEquals(expectedHeader.getProgramHeaderLines().size(), observedHeader.getProgramHeaderLines().size());
        assertEquals(expectedHeader.getCommentHeaderLines().size(), observedHeader.getCommentHeaderLines().size());

        Iterable<SamRecord> observedRecords = records(tmp);
        assertEquals(Iterables.size(expectedRecords), Iterables.size(observedRecords));
    }

    private static void validateHeader(final SamHeader header) {
        assertNotNull(header);

        assertTrue(header.getHeaderLineOpt().isPresent());
        SamHeaderLine headerLine = header.getHeaderLineOpt().get();
        assertEquals("1.5", headerLine.getVn());
        assertEquals("1.5", headerLine.getFields().get("VN"));
        assertEquals("coordinate", headerLine.getSo());
        assertEquals("coordinate", headerLine.getFields().get("SO"));
        assertFalse(headerLine.containsGo());
        assertFalse(headerLine.getFields().containsKey("GO"));

        assertFalse(header.getSequenceHeaderLines().isEmpty());
        for (SamSequenceHeaderLine sequenceHeaderLine : header.getSequenceHeaderLines()) {
            if ("chr6".equals(sequenceHeaderLine.getSn())) {
                assertEquals("chr6", sequenceHeaderLine.getFields().get("SN"));
                assertEquals("170805979", sequenceHeaderLine.getLn());
                assertEquals("170805979", sequenceHeaderLine.getFields().get("LN"));
                assertFalse(sequenceHeaderLine.containsSp());
                assertFalse(sequenceHeaderLine.getFields().containsKey("SP"));
            }
        }

        assertFalse(header.getReadGroupHeaderLines().isEmpty());
        assertEquals(1, header.getReadGroupHeaderLines().size());
        SamReadGroupHeaderLine readGroupHeaderLine = header.getReadGroupHeaderLines().get(0);
        assertEquals("NA12878-1", readGroupHeaderLine.getId());
        assertEquals("NA12878-1", readGroupHeaderLine.getFields().get("ID"));
        assertEquals("NA12878-1", readGroupHeaderLine.getSm());
        assertEquals("NA12878-1", readGroupHeaderLine.getPu());
        assertEquals("illumina", readGroupHeaderLine.getPl());
        assertEquals("illumina", readGroupHeaderLine.getFields().get("PL"));

        assertFalse(header.getProgramHeaderLines().isEmpty());
        for (SamProgramHeaderLine programHeaderLine : header.getProgramHeaderLines()) {
            if ("bwa_3".equals(programHeaderLine.getId())) {
                assertEquals("bwa_3", programHeaderLine.getFields().get("ID"));
                assertEquals("bwa", programHeaderLine.getPn());
                assertEquals("0.7.15-r1140", programHeaderLine.getVn());
                assertEquals("0.7.15-r1140", programHeaderLine.getFields().get("VN"));
            }
        }

        assertFalse(header.getCommentHeaderLines().isEmpty());
        for (SamCommentHeaderLine commentHeaderLine : header.getCommentHeaderLines()) {
            if ("all".equals(commentHeaderLine.getFields().get("ST"))
                    && "all".equals(commentHeaderLine.getFields().get("PA"))) {
                assertEquals("checksum", commentHeaderLine.getFields().get("TY"));
                assertEquals("crc32prod", commentHeaderLine.getFields().get("HA"));
            }
        }
    }

    private static void validateRecord(final SamRecord record) {
        assertNotNull(record);

        if ("ERR194147.765130386".equals(record.getQname())) {
            assertEquals(99, record.getFlag());
            assertEquals("chr20", record.getRname());
            assertEquals(60250, record.getPos());
            assertEquals(60, record.getMapq());
            assertEquals("101M", record.getCigar());
            assertEquals("=", record.getRnext());
            assertEquals(60512, record.getPnext());
            assertEquals(363, record.getTlen());
            assertEquals(
                    "ACTCCATCCCATTCCATTCCACTCCCTTCATTTCCATTCCAGTCCATTCCATTCCATTCCATTCCATTCCACTCCACTCCATTCCATTCCACTGCACTCCA",
                    record.getSeq());
            assertEquals(
                    "CCCFFFFFHHHHHJJJJJJJJJJJJJJJJJJJJJJJJJIJJJJJJIIJJJJJJJJJJJJJHIIJIJGIJJJJJJJJJJJJJIJJJJJJJJJJJGGHHHFF@",
                    record.getQual());
            assertEquals(0, record.getFieldInteger("NM"));
            assertEquals("101", record.getFieldString("MD"));
            assertEquals(101, record.getFieldInteger("AS"));
            assertEquals(55, record.getFieldInteger("XS"));
            assertEquals("NA12878-1", record.getFieldString("RG"));
            assertEquals(60, record.getFieldInteger("MQ"));
            assertEquals(3614, record.getFieldInteger("ms"));
            assertEquals(60612, record.getFieldInteger("mc"));
            assertEquals("101M", record.getFieldString("MC"));
            assertEquals("i", record.getFieldTypes().get("NM"));
            assertEquals("Z", record.getFieldTypes().get("MC"));
        }
    }

    private static void validateRecords(final Iterable<SamRecord> records) {
        assertNotNull(records);

        int count = 0;
        for (SamRecord record : records) {
            validateRecord(record);
            count++;
        }
        assertEquals(180, count);
    }

    private static URL createUrl(final String name) {
        return SamReaderTest.class.getResource(name);
    }

    private static InputStream createInputStream(final String name) {
        return SamReaderTest.class.getResourceAsStream(name);
    }

    private static File createFile(final String name) throws IOException {
        File file = File.createTempFile("samReaderTest", ".sam");
        Files.write(Resources.toByteArray(SamReaderTest.class.getResource(name)), file);
        file.deleteOnExit();
        return file;
    }
}