package picard.sam.util;
import htsjdk.samtools.util.CollectionUtil;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.List;
/**
* Tests for the ReadNameParser class.
*/
public class ReadNameParserTests {
/** Tests rapidParseInt for positive and negative numbers, as well as non-digit suffixes */
@Test
public void testRapidParseInt() {
for (int i = -100; i < 100; i++) {
Assert.assertEquals(ReadNameParser.rapidParseInt(Integer.toString(i)), i);
// trailing characters
Assert.assertEquals(ReadNameParser.rapidParseInt(Integer.toString(i)+"A"), i);
Assert.assertEquals(ReadNameParser.rapidParseInt(Integer.toString(i)+"ACGT"), i);
Assert.assertEquals(ReadNameParser.rapidParseInt(Integer.toString(i)+".1"), i);
}
}
/** Tests rapidParseInt for positive and negative numbers, as well as non-digit suffixes */
@Test
public void testRapidParseIntFails() {
List<String> values = CollectionUtil.makeList("foo", "bar", "abc123", "-foo", "f00", "-f00");
for (String s : values) {
try {
ReadNameParser.rapidParseInt(s);
Assert.fail("Should have failed to rapid-parse " + s + " as an int.");
}
catch (NumberFormatException nfe) {
/* expected */
}
}
}
/** Helper for testGetRapidDefaultReadNameRegexSplit */
private void doTestGetRapidDefaultReadNameRegexSplit(int numFields) {
final int[] inputFields = new int[3];
final int[] expectedFields = new int[3];
String readName = "";
for (int i = 0; i < numFields; i++) {
if (0 < i) readName += ":";
readName += Integer.toString(i);
}
inputFields[0] = inputFields[1] = inputFields[2] = -1;
if (numFields < 3) {
Assert.assertEquals(ReadNameParser.getLastThreeFields(readName, ':', inputFields), -1);
}
else {
Assert.assertEquals(ReadNameParser.getLastThreeFields(readName, ':', inputFields), numFields);
expectedFields[0] = expectedFields[1] = expectedFields[2] = -1;
if (0 < numFields) expectedFields[0] = numFields-3;
if (1 < numFields) expectedFields[1] = numFields-2;
if (2 < numFields) expectedFields[2] = numFields-1;
for (int i = 0; i < inputFields.length; i++) {
Assert.assertEquals(inputFields[i], expectedFields[i]);
}
}
}
/** Tests that we split the string with the correct # of fields, and modified values */
@Test
public void testGetRapidDefaultReadNameRegexSplit() {
for (int i = 1; i < 10; i++) {
doTestGetRapidDefaultReadNameRegexSplit(i);
}
}
@DataProvider(name = "testParseReadNameDataProvider")
public Object[][] testParseReadNameDataProvider() {
return new Object[][]{
{"RUNID:7:1203:2886:82292", 1203, 2886, 82292},
{"RUNID:7:1203:2884:16834", 1203, 2884, 16834}
};
}
// NB: these test fail s due to overflow in the duplicate finder test. This has been the behavior previously, so keep it for now.
@Test(dataProvider = "testParseReadNameDataProvider", enabled = true)
public void testParseReadNameOverflow(final String readName, final int tile, final int x, final int y) {
ReadNameParser parser = new ReadNameParser();
PhysicalLocation loc = new PhysicalLocationShort();
Assert.assertTrue(parser.addLocationInformation(readName, loc));
Assert.assertEquals(loc.getTile(), tile);
Assert.assertEquals(loc.getX(), (short)x); // casting to short for the overflow
Assert.assertEquals(loc.getY(), (short)y); // casting to short for the overflow
}
// NB: this test the case where we do not overflow in the duplicate finder test.
@Test(dataProvider = "testParseReadNameDataProvider", enabled = true)
public void testParseReadNameOK(final String readName, final int tile, final int x, final int y) {
ReadNameParser parser = new ReadNameParser();
PhysicalLocation loc = new PhysicalLocationInt();
Assert.assertTrue(parser.addLocationInformation(readName, loc));
Assert.assertEquals(loc.getTile(), tile);
Assert.assertEquals(loc.getX(), x); // we store ints, so we should not overflow
Assert.assertEquals(loc.getY(), y); // we store ints, so we should not overflow
}
@DataProvider(name = "testReadNameParsing")
public Object[][] testReadNameParsingDataProvider() {
final String lastThreeFieldsRegex = "(?:.*:)?([0-9]+)[^:]*:([0-9]+)[^:]*:([0-9]+)[^:]*$";
return new Object[][]{
{lastThreeFieldsRegex, "RUNID:123:000000000-ZZZZZ:1:1105:17981:23325", 1105, 17981, 23325, true},
{lastThreeFieldsRegex, "RUNID:123:000000000-ZZZZZ:1:1109:22981:17995", 1109, 22981, 17995, true},
{lastThreeFieldsRegex, "1109:22981:17995", 1109, 22981, 17995, true},
{lastThreeFieldsRegex, "RUNID:7:1203:2886:82292", 1203, 2886, 82292, true},
{lastThreeFieldsRegex, "RUNID:7:1203:2884:16834", 1203, 2884, 16834, true},
{lastThreeFieldsRegex, "1109ABC:22981DEF:17995GHI", 1109, 22981, 17995, true},
{ReadNameParser.DEFAULT_READ_NAME_REGEX, "RUNID:123:000000000-ZZZZZ:1:1105:17981:23325", 1105, 17981, 23325, true},
{ReadNameParser.DEFAULT_READ_NAME_REGEX, "RUNID:123:000000000-ZZZZZ:1:1109:22981:17995", 1109, 22981, 17995, true},
{ReadNameParser.DEFAULT_READ_NAME_REGEX, "1109:22981:17995", 1109, 22981, 17995, false},
{ReadNameParser.DEFAULT_READ_NAME_REGEX, "RUNID:7:1203:2886:82292", 1203, 2886, 82292, true},
{ReadNameParser.DEFAULT_READ_NAME_REGEX, "RUNID:7:1203:2884:16834", 1203, 2884, 16834, true}
};
}
@Test(dataProvider = "testReadNameParsing")
public void testReadNameParsing(final String readNameRegex, final String readName, final int tile, final int x, final int y, final boolean addLocationInformationSucceeds) {
final ReadNameParser parser = new ReadNameParser(readNameRegex);
final PhysicalLocationInt loc = new PhysicalLocationInt();
Assert.assertEquals(parser.addLocationInformation(readName, loc), addLocationInformationSucceeds);
if (addLocationInformationSucceeds) { // just check the location
Assert.assertEquals(loc.getTile(), tile);
Assert.assertEquals(loc.getX(), x);
Assert.assertEquals(loc.getY(), y);
}
else if (readNameRegex == ReadNameParser.DEFAULT_READ_NAME_REGEX) { // additional testing on the default regex
int[] tokens = new int[3];
ReadNameParser.getLastThreeFields(readName, ':', tokens);
Assert.assertEquals(tokens[0], tile);
Assert.assertEquals(tokens[1], x);
Assert.assertEquals(tokens[2], y);
}
}
}