diff --git a/protected/java/test/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperIntegrationTest.java b/protected/java/test/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperIntegrationTest.java
index d55a923dc..300d7f5da 100644
--- a/protected/java/test/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperIntegrationTest.java
+++ b/protected/java/test/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperIntegrationTest.java
@@ -288,9 +288,10 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest {
@Test
public void testNsInCigar() {
- WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ final WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
"-T UnifiedGenotyper --disableDithering -R " + b37KGReference + " --no_cmdline_in_header -I " + privateTestDir + "testWithNs.bam -o %s -L 8:141813600-141813700 -out_mode EMIT_ALL_SITES", 1,
- Arrays.asList("2ae3fd39c53a6954d32faed8703adfe8"));
+ UserException.UnsupportedCigarOperatorException.class);
+
executeTest("test calling on reads with Ns in CIGAR", spec);
}
}
diff --git a/public/java/src/org/broadinstitute/sting/gatk/arguments/ValidationExclusion.java b/public/java/src/org/broadinstitute/sting/gatk/arguments/ValidationExclusion.java
index f8f56f89e..75a68d978 100644
--- a/public/java/src/org/broadinstitute/sting/gatk/arguments/ValidationExclusion.java
+++ b/public/java/src/org/broadinstitute/sting/gatk/arguments/ValidationExclusion.java
@@ -36,6 +36,8 @@ public class ValidationExclusion {
// our validation options
public enum TYPE {
+ ALLOW_N_CIGAR_READS, // ignore the presence of N operators in CIGARs: do not blow up and process reads that contain one or more N operators.
+ // This exclusion does not have effect on reads that get filtered {@see MalformedReadFilter}.
ALLOW_UNINDEXED_BAM, // allow bam files that do not have an index; we'll traverse them using monolithic shard
ALLOW_UNSET_BAM_SORT_ORDER, // assume that the bam is sorted, even if the SO (sort-order) flag is not set
NO_READ_ORDER_VERIFICATION, // do not validate that the reads are in order as we take them from the bam file
diff --git a/public/java/src/org/broadinstitute/sting/gatk/filters/MalformedReadFilter.java b/public/java/src/org/broadinstitute/sting/gatk/filters/MalformedReadFilter.java
index f7d1d0297..a15870a22 100644
--- a/public/java/src/org/broadinstitute/sting/gatk/filters/MalformedReadFilter.java
+++ b/public/java/src/org/broadinstitute/sting/gatk/filters/MalformedReadFilter.java
@@ -25,14 +25,16 @@
package org.broadinstitute.sting.gatk.filters;
-import net.sf.samtools.SAMFileHeader;
-import net.sf.samtools.SAMRecord;
-import net.sf.samtools.SAMSequenceRecord;
-import net.sf.samtools.SAMTagUtil;
+import net.sf.samtools.*;
import org.broadinstitute.sting.commandline.Argument;
import org.broadinstitute.sting.gatk.GenomeAnalysisEngine;
+import org.broadinstitute.sting.gatk.ReadProperties;
+import org.broadinstitute.sting.gatk.arguments.ValidationExclusion;
+import org.broadinstitute.sting.gatk.datasources.reads.SAMDataSource;
import org.broadinstitute.sting.utils.exceptions.UserException;
+import java.util.Collections;
+
/**
* Filter out malformed reads.
*
@@ -40,20 +42,46 @@ import org.broadinstitute.sting.utils.exceptions.UserException;
* @version 0.1
*/
public class MalformedReadFilter extends ReadFilter {
+
+
+ private static final String FILTER_READS_WITH_N_CIGAR_ARGUMENT_FULL_NAME = "filter_reads_with_N_cigar" ;
+
private SAMFileHeader header;
+ @Argument(fullName = FILTER_READS_WITH_N_CIGAR_ARGUMENT_FULL_NAME, shortName = "filterRNC", doc = "filter out reads with CIGAR containing the N operator, instead of stop processing and report an error.", required = false)
+ boolean filterReadsWithNCigar = false;
+
+
@Argument(fullName = "filter_mismatching_base_and_quals", shortName = "filterMBQ", doc = "if a read has mismatching number of bases and base qualities, filter out the read instead of blowing up.", required = false)
boolean filterMismatchingBaseAndQuals = false;
@Argument(fullName = "filter_bases_not_stored", shortName = "filterNoBases", doc = "if a read has no stored bases (i.e. a '*'), filter out the read instead of blowing up.", required = false)
boolean filterBasesNotStored = false;
+ /**
+ * Indicates the applicable validation exclusions
+ */
+ private boolean allowNCigars;
+
@Override
- public void initialize(GenomeAnalysisEngine engine) {
- this.header = engine.getSAMFileHeader();
+ public void initialize(final GenomeAnalysisEngine engine) {
+ header = engine.getSAMFileHeader();
+ ValidationExclusion validationExclusions = null;
+ final SAMDataSource rds = engine.getReadsDataSource();
+ if (rds != null) {
+ final ReadProperties rps = rds.getReadsInfo();
+ if (rps != null) {
+ validationExclusions = rps.getValidationExclusionList();
+ }
+ }
+ if (validationExclusions == null) {
+ allowNCigars = false;
+ } else {
+ allowNCigars = validationExclusions.contains(ValidationExclusion.TYPE.ALLOW_N_CIGAR_READS);
+ }
}
- public boolean filterOut(SAMRecord read) {
+ public boolean filterOut(final SAMRecord read) {
// slowly changing the behavior to blow up first and filtering out if a parameter is explicitly provided
return !checkInvalidAlignmentStart(read) ||
!checkInvalidAlignmentEnd(read) ||
@@ -61,7 +89,8 @@ public class MalformedReadFilter extends ReadFilter {
!checkHasReadGroup(read) ||
!checkMismatchingBasesAndQuals(read, filterMismatchingBaseAndQuals) ||
!checkCigarDisagreesWithAlignment(read) ||
- !checkSeqStored(read, filterBasesNotStored);
+ !checkSeqStored(read, filterBasesNotStored) ||
+ !checkCigarIsSupported(read,filterReadsWithNCigar,allowNCigars);
}
private static boolean checkHasReadGroup(final SAMRecord read) {
@@ -80,7 +109,7 @@ public class MalformedReadFilter extends ReadFilter {
* @param read The read to validate.
* @return true if read start is valid, false otherwise.
*/
- private static boolean checkInvalidAlignmentStart( SAMRecord read ) {
+ private static boolean checkInvalidAlignmentStart(final SAMRecord read ) {
// read is not flagged as 'unmapped', but alignment start is NO_ALIGNMENT_START
if( !read.getReadUnmappedFlag() && read.getAlignmentStart() == SAMRecord.NO_ALIGNMENT_START )
return false;
@@ -95,7 +124,7 @@ public class MalformedReadFilter extends ReadFilter {
* @param read The read to validate.
* @return true if read end is valid, false otherwise.
*/
- private static boolean checkInvalidAlignmentEnd( SAMRecord read ) {
+ private static boolean checkInvalidAlignmentEnd(final SAMRecord read ) {
// Alignment aligns to negative number of bases in the reference.
if( !read.getReadUnmappedFlag() && read.getAlignmentEnd() != -1 && (read.getAlignmentEnd()-read.getAlignmentStart()+1)<0 )
return false;
@@ -108,11 +137,11 @@ public class MalformedReadFilter extends ReadFilter {
* @param read The read to verify.
* @return true if alignment agrees with header, false othrewise.
*/
- private static boolean checkAlignmentDisagreesWithHeader( SAMFileHeader header, SAMRecord read ) {
+ private static boolean checkAlignmentDisagreesWithHeader(final SAMFileHeader header, final SAMRecord read ) {
// Read is aligned to nonexistent contig
if( read.getReferenceIndex() == SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX && read.getAlignmentStart() != SAMRecord.NO_ALIGNMENT_START )
return false;
- SAMSequenceRecord contigHeader = header.getSequence( read.getReferenceIndex() );
+ final SAMSequenceRecord contigHeader = header.getSequence( read.getReferenceIndex() );
// Read is aligned to a point after the end of the contig
if( !read.getReadUnmappedFlag() && read.getAlignmentStart() > contigHeader.getSequenceLength() )
return false;
@@ -124,7 +153,7 @@ public class MalformedReadFilter extends ReadFilter {
* @param read The read to validate.
* @return true if cigar agrees with alignment, false otherwise.
*/
- private static boolean checkCigarDisagreesWithAlignment(SAMRecord read) {
+ private static boolean checkCigarDisagreesWithAlignment(final SAMRecord read) {
// Read has a valid alignment start, but the CIGAR string is empty
if( !read.getReadUnmappedFlag() &&
read.getAlignmentStart() != -1 &&
@@ -134,13 +163,72 @@ public class MalformedReadFilter extends ReadFilter {
return true;
}
+ /**
+ * Check for unsupported CIGAR operators.
+ * Currently the N operator is not supported.
+ * @param read The read to validate.
+ * @param filterReadsWithNCigar whether the offending read should just
+ * be silently filtered or not.
+ * @param allowNCigars whether reads that contain N operators in their CIGARs
+ * can be processed or an exception should be thrown instead.
+ * @throws UserException.UnsupportedCigarOperatorException
+ * if {@link #filterReadsWithNCigar} is false and
+ * the input read has some unsupported operation.
+ * @return true if the read CIGAR operations are
+ * fully supported, otherwise false, as long as
+ * no exception has been thrown.
+ */
+ private static boolean checkCigarIsSupported(final SAMRecord read, final boolean filterReadsWithNCigar, final boolean allowNCigars) {
+ if( containsNOperator(read)) {
+ if (! filterReadsWithNCigar && !allowNCigars) {
+ throw new UserException.UnsupportedCigarOperatorException(
+ CigarOperator.N,read,
+ "Perhaps you are"
+ + " trying to use RNA-Seq data?"
+ + " While we are currently actively working to"
+ + " support this data type unfortunately the"
+ + " GATK cannot be used with this data in its"
+ + " current form. You have the option of either"
+ + " filtering out all reads with operator "
+ + CigarOperator.N + " in their CIGAR string"
+ + " (please add --"
+ + FILTER_READS_WITH_N_CIGAR_ARGUMENT_FULL_NAME
+ + " to your command line) or"
+ + " assume the risk of processing those reads as they"
+ + " are including the pertinent unsafe flag (please add -U"
+ + ' ' + ValidationExclusion.TYPE.ALLOW_N_CIGAR_READS
+ + " to your command line). Notice however that if you were"
+ + " to choose the latter, an unspecified subset of the"
+ + " analytical outputs of an unspecified subset of the tools"
+ + " will become unpredictable. Consequently the GATK team"
+ + " might well not be able to provide you with the usual support"
+ + " with any issue regarding any output");
+ }
+ return ! filterReadsWithNCigar;
+ }
+ return true;
+ }
+
+ private static boolean containsNOperator(final SAMRecord read) {
+ final Cigar cigar = read.getCigar();
+ if (cigar == null) {
+ return false;
+ }
+ for (final CigarElement ce : cigar.getCigarElements()) {
+ if (ce.getOperator() == CigarOperator.N) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Check if the read has the same number of bases and base qualities
* @param read the read to validate
* @return true if they have the same number. False otherwise.
*/
- private static boolean checkMismatchingBasesAndQuals(SAMRecord read, boolean filterMismatchingBaseAndQuals) {
- boolean result;
+ private static boolean checkMismatchingBasesAndQuals(final SAMRecord read, final boolean filterMismatchingBaseAndQuals) {
+ final boolean result;
if (read.getReadLength() == read.getBaseQualities().length)
result = true;
else if (filterMismatchingBaseAndQuals)
diff --git a/public/java/src/org/broadinstitute/sting/utils/exceptions/UserException.java b/public/java/src/org/broadinstitute/sting/utils/exceptions/UserException.java
index 3abe5a7f4..0e95fd158 100644
--- a/public/java/src/org/broadinstitute/sting/utils/exceptions/UserException.java
+++ b/public/java/src/org/broadinstitute/sting/utils/exceptions/UserException.java
@@ -25,6 +25,7 @@
package org.broadinstitute.sting.utils.exceptions;
+import net.sf.samtools.CigarOperator;
import net.sf.samtools.SAMFileHeader;
import net.sf.samtools.SAMRecord;
import net.sf.samtools.SAMSequenceDictionary;
@@ -87,6 +88,19 @@ public class UserException extends ReviewedStingException {
}
}
+ public static class UnsupportedCigarOperatorException extends UserException {
+ public UnsupportedCigarOperatorException(final CigarOperator co, final SAMRecord read, final String message) {
+ super(String.format(
+ "Unsupported CIGAR operator %s in read %s at %s:%d. %s",
+ co,
+ read.getReadName(),
+ read.getReferenceName(),
+ read.getAlignmentStart(),
+ message));
+ }
+ }
+
+
public static class MalformedGenomeLoc extends UserException {
public MalformedGenomeLoc(String message, GenomeLoc loc) {
super(String.format("Badly formed genome loc: %s: %s", message, loc));
diff --git a/public/java/test/org/broadinstitute/sting/gatk/EngineFeaturesIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/EngineFeaturesIntegrationTest.java
index 6cfa90d90..b5b82f869 100644
--- a/public/java/test/org/broadinstitute/sting/gatk/EngineFeaturesIntegrationTest.java
+++ b/public/java/test/org/broadinstitute/sting/gatk/EngineFeaturesIntegrationTest.java
@@ -131,6 +131,7 @@ public class EngineFeaturesIntegrationTest extends WalkerTest {
final String root = "-T ErrorThrowing -R " + exampleFASTA;
final String args = root + cfg.args + " -E " + cfg.expectedException.getSimpleName();
WalkerTestSpec spec = new WalkerTestSpec(args, 0, cfg.expectedException);
+
executeTest(cfg.toString(), spec);
}
}
diff --git a/public/java/test/org/broadinstitute/sting/gatk/filters/AllowNCigarMalformedReadFilterUnitTest.java b/public/java/test/org/broadinstitute/sting/gatk/filters/AllowNCigarMalformedReadFilterUnitTest.java
new file mode 100644
index 000000000..d169bf7e9
--- /dev/null
+++ b/public/java/test/org/broadinstitute/sting/gatk/filters/AllowNCigarMalformedReadFilterUnitTest.java
@@ -0,0 +1,77 @@
+/*
+* Copyright (c) 2012 The 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.broadinstitute.sting.gatk.filters;
+
+
+import net.sf.samtools.SAMRecord;
+import org.broadinstitute.sting.gatk.arguments.ValidationExclusion;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.Collections;
+
+
+/**
+ * Tests for the {@link MalformedReadFilter} when the unsafe flag
+ * {@link ValidationExclusion.TYPE#ALLOW_N_CIGAR_READS} is set.
+ *
+ * @author Valentin Ruano-Rubio
+ * @since 6/6/13
+ */
+public class AllowNCigarMalformedReadFilterUnitTest extends MalformedReadFilterUnitTest {
+
+
+ @Override
+ protected ValidationExclusion composeValidationExclusion() {
+ return new ValidationExclusion(Collections.singletonList(ValidationExclusion.TYPE.ALLOW_N_CIGAR_READS));
+ }
+
+
+ @Test(enabled = true,
+ dataProvider= "UnsupportedCigarOperatorDataProvider")
+ @CigarOperatorTest(CigarOperatorTest.Outcome.IGNORE)
+ public void testCigarNOperatorFilterIgnore(final String cigarString) {
+
+ final MalformedReadFilter filter = buildMalformedReadFilter(false);
+ final SAMRecord nContainingCigarRead = buildSAMRecord(cigarString);
+ Assert.assertFalse(filter.filterOut(nContainingCigarRead),
+ "filters out N containing Cigar when it should ignore the fact");
+ }
+
+ @Test(enabled = false)
+ @Override
+ public void testCigarNOperatorFilterException(final String cigarString) {
+ // Nothing to do here.
+ // Just deactivates the parents test case.
+ }
+
+
+
+
+
+
+
+}
diff --git a/public/java/test/org/broadinstitute/sting/gatk/filters/MalformedReadFilterUnitTest.java b/public/java/test/org/broadinstitute/sting/gatk/filters/MalformedReadFilterUnitTest.java
index 981d54d54..0d8515dde 100644
--- a/public/java/test/org/broadinstitute/sting/gatk/filters/MalformedReadFilterUnitTest.java
+++ b/public/java/test/org/broadinstitute/sting/gatk/filters/MalformedReadFilterUnitTest.java
@@ -25,11 +25,25 @@
package org.broadinstitute.sting.gatk.filters;
-import org.broadinstitute.sting.utils.exceptions.UserException;
+
+import net.sf.samtools.Cigar;
+import net.sf.samtools.SAMFileHeader;
+import net.sf.samtools.SAMRecord;
+import net.sf.samtools.TextCigarCodec;
+import org.broadinstitute.sting.gatk.GenomeAnalysisEngine;
+import org.broadinstitute.sting.gatk.arguments.ValidationExclusion;
+import org.broadinstitute.sting.gatk.datasources.reads.SAMDataSource;
import org.broadinstitute.sting.utils.sam.ArtificialSAMUtils;
import org.broadinstitute.sting.utils.sam.GATKSAMRecord;
import org.testng.Assert;
+import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
+import org.broadinstitute.sting.utils.exceptions.UserException;
+import org.broadinstitute.sting.utils.exceptions.UserException.UnsupportedCigarOperatorException;
+
+import java.lang.annotation.*;
+import java.lang.reflect.Method;
+import java.util.*;
/**
@@ -38,14 +52,14 @@ import org.testng.annotations.Test;
* @author Eric Banks
* @since 3/14/13
*/
-public class MalformedReadFilterUnitTest {
+public class MalformedReadFilterUnitTest extends ReadFilterTest {
//////////////////////////////////////
// Test the checkSeqStored() method //
//////////////////////////////////////
@Test(enabled = true)
- public void testcheckSeqStored () {
+ public void testCheckSeqStored () {
final GATKSAMRecord goodRead = ArtificialSAMUtils.createArtificialRead(new byte[]{(byte)'A'}, new byte[]{(byte)'A'}, "1M");
final GATKSAMRecord badRead = ArtificialSAMUtils.createArtificialRead(new byte[]{}, new byte[]{}, "1M");
@@ -59,4 +73,174 @@ public class MalformedReadFilterUnitTest {
Assert.assertTrue(false, "We should have exceptioned out in the previous line");
} catch (UserException e) { }
}
+
+ @Test(enabled = true, dataProvider= "UnsupportedCigarOperatorDataProvider")
+ @CigarOperatorTest(CigarOperatorTest.Outcome.FILTER)
+ public void testCigarNOperatorFilterTruePositive(String cigarString) {
+
+ final MalformedReadFilter filter = buildMalformedReadFilter(true);
+ final SAMRecord nContainingCigarRead = buildSAMRecord(cigarString);
+ Assert.assertTrue(filter.filterOut(nContainingCigarRead),
+ " Did not filtered out a N containing CIGAR read");
+ }
+
+ @Test(enabled = true, dataProvider= "UnsupportedCigarOperatorDataProvider")
+ @CigarOperatorTest(CigarOperatorTest.Outcome.ACCEPT)
+ public void testCigarNOperatorFilterTrueNegative(String cigarString) {
+
+ final MalformedReadFilter filter = buildMalformedReadFilter(true);
+ final SAMRecord nonNContainingCigarRead = buildSAMRecord(cigarString);
+ Assert.assertFalse(filter.filterOut(nonNContainingCigarRead),
+ " Filtered out a non-N containing CIGAR read");
+ }
+
+ @Test(enabled = true,
+ expectedExceptions = UnsupportedCigarOperatorException.class,
+ dataProvider= "UnsupportedCigarOperatorDataProvider")
+ @CigarOperatorTest(CigarOperatorTest.Outcome.EXCEPTION)
+ public void testCigarNOperatorFilterException(final String cigarString) {
+
+ final MalformedReadFilter filter = buildMalformedReadFilter(false);
+ final SAMRecord nContainingCigarRead = buildSAMRecord(cigarString);
+
+ filter.filterOut(nContainingCigarRead);
+ }
+
+ @Test(enabled = true, dataProvider="UnsupportedCigarOperatorDataProvider")
+ @CigarOperatorTest(CigarOperatorTest.Outcome.ACCEPT)
+ public void testCigarNOperatorFilterControl(final String cigarString) {
+
+ final MalformedReadFilter filter = buildMalformedReadFilter(false);
+ final SAMRecord nonNContainingCigarRead = buildSAMRecord(cigarString);
+
+ Assert.assertFalse(filter.filterOut(nonNContainingCigarRead));
+ }
+
+ protected SAMRecord buildSAMRecord(final String cigarString) {
+ final Cigar nContainingCigar = TextCigarCodec.getSingleton().decode(cigarString);
+ return this.createRead(nContainingCigar, 1, 0, 10);
+ }
+
+ protected MalformedReadFilter buildMalformedReadFilter(final boolean filterRNO) {
+ return buildMalformedReadFiter(filterRNO,new ValidationExclusion.TYPE[] {});
+ }
+
+ protected MalformedReadFilter buildMalformedReadFiter(boolean filterRNO, final ValidationExclusion.TYPE... excl) {
+ final ValidationExclusion ve = new ValidationExclusion(Arrays.asList(excl));
+
+ final MalformedReadFilter filter = new MalformedReadFilter();
+
+ final SAMFileHeader h = getHeader();
+ final SAMDataSource ds = getDataSource();
+
+ final GenomeAnalysisEngine gae = new GenomeAnalysisEngine() {
+ @Override
+ public SAMFileHeader getSAMFileHeader() {
+ return h;
+ }
+
+ @Override
+ public SAMDataSource getReadsDataSource() {
+ return ds;
+ }
+ };
+ filter.initialize(gae);
+ filter.filterReadsWithNCigar = filterRNO;
+ return filter;
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ @Inherited
+ protected @interface CigarOperatorTest {
+
+ enum Outcome {
+ ANY,ACCEPT,FILTER,EXCEPTION,IGNORE;
+
+ public boolean appliesTo (String cigar) {
+ boolean hasN = cigar.indexOf('N') != -1;
+ switch (this) {
+ case ANY: return true;
+ case ACCEPT: return !hasN;
+ case IGNORE: return hasN;
+ case FILTER:
+ case EXCEPTION:
+ default:
+ return hasN;
+
+ }
+ }
+ }
+
+ Outcome value() default Outcome.ANY;
+ }
+
+ /**
+ * Cigar test data for unsupported operator test.
+ * Each element of this array corresponds to a test case. In turn the first element of the test case array is the
+ * Cigar string for that test case and the second indicates whether it should be filtered due to the presence of a
+ * unsupported operator
+ */
+ private static final String[] TEST_CIGARS = {
+ "101M10D20I10M",
+ "6M14N5M",
+ "1N",
+ "101M",
+ "110N",
+ "2N4M",
+ "4M2N",
+ "3M1I1M",
+ "1M2I2M",
+ "1M10N1I1M",
+ "1M1I1D",
+ "11N12M1I34M12N"
+ };
+
+ @DataProvider(name= "UnsupportedCigarOperatorDataProvider")
+ public Iterator