diff --git a/src/main/java/htsjdk/samtools/SAMRecord.java b/src/main/java/htsjdk/samtools/SAMRecord.java index dcd1a230b..a22ded540 100644 --- a/src/main/java/htsjdk/samtools/SAMRecord.java +++ b/src/main/java/htsjdk/samtools/SAMRecord.java @@ -1397,7 +1397,7 @@ protected void setAttribute(final short tag, final Object value) { * @deprecated * The attribute type and value checks have been moved directly into - * {@code SAMBinaryTagAndValue}. + * {@link SAMBinaryTagAndValue}. */ @Deprecated protected static boolean isAllowedAttributeValue(final Object value) { diff --git a/src/main/java/htsjdk/samtools/TextTagCodec.java b/src/main/java/htsjdk/samtools/TextTagCodec.java index 0fae20269..60363e160 100644 --- a/src/main/java/htsjdk/samtools/TextTagCodec.java +++ b/src/main/java/htsjdk/samtools/TextTagCodec.java @@ -41,6 +41,7 @@ * instance is used in multiple threads. */ public class TextTagCodec { + // 3 fields for non-empty strings 2 fields if the string is empty. private static final int NUM_TAG_FIELDS = 3; /** @@ -149,12 +150,12 @@ public String encodeUntypedTag(final String tagName, final Object value) { */ public Map.Entry decode(final String tag) { final int numFields = StringUtil.splitConcatenateExcessTokens(tag, fields, ':'); - if (numFields != TextTagCodec.NUM_TAG_FIELDS) { + if (numFields != TextTagCodec.NUM_TAG_FIELDS && numFields != TextTagCodec.NUM_TAG_FIELDS - 1) { throw new SAMFormatException("Not enough fields in tag '" + tag + "'"); } final String key = fields[0]; final String type = fields[1]; - final String stringVal = fields[2]; + final String stringVal = numFields == TextTagCodec.NUM_TAG_FIELDS ? fields[2] : ""; final Object val = convertStringToObject(type, stringVal); return new Map.Entry() { public String getKey() { diff --git a/src/test/java/htsjdk/samtools/SAMIntegerTagTest.java b/src/test/java/htsjdk/samtools/SAMIntegerTagTest.java index 2d78a78dc..133062a15 100644 --- a/src/test/java/htsjdk/samtools/SAMIntegerTagTest.java +++ b/src/test/java/htsjdk/samtools/SAMIntegerTagTest.java @@ -98,6 +98,52 @@ public void testGetTypedAttributeMethods() throws Exception { Assert.assertEquals(rec.getIntegerAttribute(INTEGER_TAG).intValue(), 1); } + + @DataProvider + public Object[][] formatsAndValues(){ + return new Object[][]{ + new Object[]{"sam","Hello World!"}, + new Object[]{"bam","Hello World!"}, + new Object[]{"cram","Hello World!"}, + new Object[]{"cram",""}, + new Object[]{"bam",""}, + new Object[]{"sam",""}, + }; + } + /** + * Should be able to write empty and non-empty strings + */ + @Test(dataProvider = "formatsAndValues") + public void testWriteAndReadStrings(final String format,final String value) throws Exception { + final SAMRecord rec = createSamRecord(); + rec.setAttribute(STRING_TAG, value); + writeAndReadSamRecord(format, rec); + Assert.assertEquals(rec.getStringAttribute(STRING_TAG),value); + } + + + @DataProvider + public Object[][] formatsAndValues2(){ + return new Object[][]{ + new Object[]{"sam",'a'}, + new Object[]{"bam",'a'}, + new Object[]{"cram",'a'}, + new Object[]{"cram",null}, + new Object[]{"bam",null}, + new Object[]{"sam",null}, + }; + } + /** + * Should be able to write empty and non-empty strings + */ + @Test(dataProvider = "formatsAndValues2") + public void testWriteAndReadCharacters(final String format,final Character value) throws Exception { + final SAMRecord rec = createSamRecord(); + rec.setAttribute(STRING_TAG, value); + writeAndReadSamRecord(format, rec); + Assert.assertEquals(rec.getCharacterAttribute(STRING_TAG),value); + } + /** * Should be an exception if a typed attribute call is made for the wrong type. */ diff --git a/src/test/java/htsjdk/samtools/SAMRecordUnitTest.java b/src/test/java/htsjdk/samtools/SAMRecordUnitTest.java index a8f06e45a..15b732607 100644 --- a/src/test/java/htsjdk/samtools/SAMRecordUnitTest.java +++ b/src/test/java/htsjdk/samtools/SAMRecordUnitTest.java @@ -417,6 +417,19 @@ public void test_isAllowedAttributeDataType() { Assert.assertFalse(SAMRecord.isAllowedAttributeValue(new Long(Integer.MIN_VALUE - 1L))); } + @Test() + public void test_setAttribute_empty_string() { + final SAMFileHeader header = new SAMFileHeader(); + final SAMRecord record = new SAMRecord(header); + Assert.assertNull(record.getStringAttribute(SAMTag.MD.name())); + record.setAttribute(SAMTag.MD.name(), ""); + Assert.assertNotNull(record.getStringAttribute(SAMTag.MD.name())); + Assert.assertEquals(record.getStringAttribute(SAMTag.MD.name()),""); + record.setAttribute(SAMTag.MD.name(), null); + Assert.assertNull(record.getStringAttribute(SAMTag.MD.name())); + } + + @Test(expectedExceptions = IllegalArgumentException.class) public void test_setAttribute_unsigned_int_negative() { SAMFileHeader header = new SAMFileHeader();