Skip to content
Snippets Groups Projects
Commit aa84be3d authored by bow's avatar bow
Browse files

Merge branch 'develop' into feature-wipereads

parents c8af4d54 14790fa3
No related branches found
No related tags found
No related merge requests found
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>nl.lumc.sasc</groupId> <groupId>nl.lumc.sasc</groupId>
<artifactId>BiopetFramework</artifactId> <artifactId>BiopetFramework</artifactId>
<version>0.2.0-DEV</version> <version>0.2.0-DEV</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>BiopetFramework</name> <name>BiopetFramework</name>
<url>http://maven.apache.org</url> <url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<sting.unpack.phase>prepare-package</sting.unpack.phase>
<sting.shade.phase>package</sting.shade.phase>
<app.main.class>nl.lumc.sasc.biopet.core.BiopetExecutable</app.main.class>
</properties>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<sting.unpack.phase>prepare-package</sting.unpack.phase>
<sting.shade.phase>package</sting.shade.phase>
<sting.binary-dist.name>SASC-Pipelines</sting.binary-dist.name>
<app.main.class>nl.lumc.sasc.biopet.core.BiopetExecutable</app.main.class>
</properties>
<repositories> <repositories>
<repository> <repository>
<id>biojava-maven-repo</id> <id>biojava-maven-repo</id>
<name>BioJava repository</name> <name>BioJava repository</name>
<url>http://www.biojava.org/download/maven/</url> <url>http://www.biojava.org/download/maven/</url>
</repository> </repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.testng</groupId> <groupId>org.testng</groupId>
<artifactId>testng</artifactId> <artifactId>testng</artifactId>
<version>6.8</version> <version>6.8</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.scalatest</groupId> <groupId>org.scalatest</groupId>
...@@ -68,9 +67,9 @@ ...@@ -68,9 +67,9 @@
<version>18.0</version> <version>18.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.scopt</groupId> <groupId>com.github.scopt</groupId>
<artifactId>scopt_2.10</artifactId> <artifactId>scopt_2.10</artifactId>
<version>3.2.0</version> <version>3.2.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
...@@ -81,16 +80,16 @@ ...@@ -81,16 +80,16 @@
<build> <build>
<resources> <resources>
<resource> <resource>
<directory>src/main/scripts</directory> <directory>src/main/scripts</directory>
<includes> <includes>
<include>**/*</include> <include>**/*</include>
</includes> </includes>
</resource> </resource>
<resource> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
<includes> <includes>
<include>**/*</include> <include>**/*</include>
</includes> </includes>
</resource> </resource>
</resources> </resources>
<plugins> <plugins>
...@@ -102,7 +101,7 @@ ...@@ -102,7 +101,7 @@
<execution> <execution>
<goals> <goals>
<goal>revision</goal> <goal>revision</goal>
</goals> </goals>
</execution> </execution>
</executions> </executions>
...@@ -141,9 +140,10 @@ ...@@ -141,9 +140,10 @@
</goals> </goals>
<configuration> <configuration>
<args> <args>
<!-- <arg>-make:transitive</arg>-->
<arg>-dependencyfile</arg> <arg>-dependencyfile</arg>
<arg>${project.build.directory}/.scala_dependencies</arg> <arg>${project.build.directory}/.scala_dependencies</arg>
<arg>-deprecation</arg>
<arg>-feature</arg>
</args> </args>
</configuration> </configuration>
</execution> </execution>
...@@ -154,7 +154,7 @@ ...@@ -154,7 +154,7 @@
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>2.5</version> <version>2.5</version>
<configuration> <configuration>
<archive> <archive>
<manifest> <manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries> <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
...@@ -163,50 +163,50 @@ ...@@ -163,50 +163,50 @@
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>2.3</version> <version>2.3</version>
<configuration> <configuration>
<finalName>Biopet-${project.version}-${git.commit.id.abbrev}</finalName> <finalName>Biopet-${project.version}-${git.commit.id.abbrev}</finalName>
<transformers> <transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries> <manifestEntries>
<Main-Class>${app.main.class}</Main-Class> <Main-Class>${app.main.class}</Main-Class>
<X-Compile-Source-JDK>${maven.compile.source}</X-Compile-Source-JDK> <X-Compile-Source-JDK>${maven.compile.source}</X-Compile-Source-JDK>
<X-Compile-Target-JDK>${maven.compile.target}</X-Compile-Target-JDK> <X-Compile-Target-JDK>${maven.compile.target}</X-Compile-Target-JDK>
</manifestEntries> </manifestEntries>
</transformer> </transformer>
</transformers> </transformers>
<filters> <filters>
<filter> <filter>
<artifact>org.broadinstitute.gatk:gatk-queue-package-distribution</artifact> <artifact>org.broadinstitute.gatk:gatk-queue-package-distribution</artifact>
<includes> <includes>
<include>*/**</include> <include>*/**</include>
<include>org/simpleframework/**</include> <include>org/simpleframework/**</include>
<include>org/jets3t/**</include> <include>org/jets3t/**</include>
<include>com/sun/**</include> <include>com/sun/**</include>
<include>org/ggf/**</include> <include>org/ggf/**</include>
<include>picard/**</include> <include>picard/**</include>
<include>htsjdk/**</include> <include>htsjdk/**</include>
<include>javassist/**</include> <include>javassist/**</include>
<include>com/google/**</include> <include>com/google/**</include>
<include>org/reflections/</include> <include>org/reflections/</include>
<include>org/jgrapht/**</include> <include>org/jgrapht/**</include>
<include>org/broadinstitute/**</include> <include>org/broadinstitute/**</include>
<include>org/apache/**</include> <include>org/apache/**</include>
<include>scala/tools/nsc/reporters/**</include> <include>scala/tools/nsc/reporters/**</include>
</includes> </includes>
</filter> </filter>
</filters> </filters>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
<goals> <goals>
<goal>shade</goal> <goal>shade</goal>
</goals> </goals>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
...@@ -221,33 +221,35 @@ ...@@ -221,33 +221,35 @@
<artifactId>scalariform-maven-plugin</artifactId> <artifactId>scalariform-maven-plugin</artifactId>
<version>0.1.4</version> <version>0.1.4</version>
<executions> <executions>
<execution> <execution>
<phase>process-sources</phase> <phase>process-sources</phase>
<goals> <goals>
<goal>format</goal> <goal>format</goal>
</goals> </goals>
<configuration> <configuration>
<rewriteArrowSymbols>false</rewriteArrowSymbols> <rewriteArrowSymbols>false</rewriteArrowSymbols>
<alignParameters>true</alignParameters> <alignParameters>true</alignParameters>
<alignSingleLineCaseStatements_maxArrowIndent>40</alignSingleLineCaseStatements_maxArrowIndent> <alignSingleLineCaseStatements_maxArrowIndent>40
<alignSingleLineCaseStatements>true</alignSingleLineCaseStatements> </alignSingleLineCaseStatements_maxArrowIndent>
<compactStringConcatenation>false</compactStringConcatenation> <alignSingleLineCaseStatements>true</alignSingleLineCaseStatements>
<compactControlReadability>false</compactControlReadability> <compactStringConcatenation>false</compactStringConcatenation>
<doubleIndentClassDeclaration>false</doubleIndentClassDeclaration> <compactControlReadability>false</compactControlReadability>
<formatXml>true</formatXml> <doubleIndentClassDeclaration>false</doubleIndentClassDeclaration>
<indentLocalDefs>false</indentLocalDefs> <formatXml>true</formatXml>
<indentPackageBlocks>true</indentPackageBlocks> <indentLocalDefs>false</indentLocalDefs>
<indentSpaces>2</indentSpaces> <indentPackageBlocks>true</indentPackageBlocks>
<placeScaladocAsterisksBeneathSecondAsterisk>false</placeScaladocAsterisksBeneathSecondAsterisk> <indentSpaces>2</indentSpaces>
<preserveDanglingCloseParenthesis>true</preserveDanglingCloseParenthesis> <placeScaladocAsterisksBeneathSecondAsterisk>false
<preserveSpaceBeforeArguments>false</preserveSpaceBeforeArguments> </placeScaladocAsterisksBeneathSecondAsterisk>
<rewriteArrowSymbols>false</rewriteArrowSymbols> <preserveDanglingCloseParenthesis>true</preserveDanglingCloseParenthesis>
<spaceBeforeColon>false</spaceBeforeColon> <preserveSpaceBeforeArguments>false</preserveSpaceBeforeArguments>
<spaceInsideBrackets>false</spaceInsideBrackets> <rewriteArrowSymbols>false</rewriteArrowSymbols>
<spaceInsideParentheses>false</spaceInsideParentheses> <spaceBeforeColon>false</spaceBeforeColon>
<spacesWithinPatternBinders>true</spacesWithinPatternBinders> <spaceInsideBrackets>false</spaceInsideBrackets>
</configuration> <spaceInsideParentheses>false</spaceInsideParentheses>
</execution> <spacesWithinPatternBinders>true</spacesWithinPatternBinders>
</configuration>
</execution>
</executions> </executions>
</plugin> </plugin>
</plugins> </plugins>
......
package nl.lumc.sasc.biopet.extensions package nl.lumc.sasc.biopet.extensions
import java.io.File import java.io.File
import scala.sys.process.Process import scala.sys.process.{ Process, ProcessLogger }
import org.broadinstitute.gatk.queue.function.InProcessFunction import org.broadinstitute.gatk.queue.function.InProcessFunction
import org.broadinstitute.gatk.utils.commandline.{ Input, Output } import org.broadinstitute.gatk.utils.commandline.{ Input, Output }
import nl.lumc.sasc.biopet.core.config.Configurable import nl.lumc.sasc.biopet.core.config.Configurable
...@@ -71,15 +71,21 @@ class Ln(val root: Configurable) extends InProcessFunction with Configurable { ...@@ -71,15 +71,21 @@ class Ln(val root: Configurable) extends InProcessFunction with Configurable {
if (relative) { if (relative) {
// workaround until we have `ln` that works with relative path (i.e. `ln -r`) // workaround until we have `ln` that works with relative path (i.e. `ln -r`)
"ln -s '" + inRelative + "' '" + outCanonical + "'" "ln -s " + inRelative + " " + outCanonical
} else { } else {
"ln -s '" + inCanonical + "' '" + outCanonical + "'" "ln -s " + inCanonical + " " + outCanonical
} }
} }
override def run { override def run {
val process = Process(cmd).run val stdout = new StringBuffer()
logger.info("cmd: '" + cmd + "', exitcode: " + process.exitValue) val stderr = new StringBuffer()
val process = Process(cmd).run(ProcessLogger(stdout append _ + "\n", stderr append _ + "\n"))
val exitcode = process.exitValue
if (exitcode != 0) {
throw new Exception("Error creating symbolic link, this was the original message: \n" + stderr)
}
logger.info("cmd: '" + cmd + "', exitcode: " + exitcode)
} }
} }
......
...@@ -19,7 +19,7 @@ import nl.lumc.sasc.biopet.core.ToolCommand ...@@ -19,7 +19,7 @@ import nl.lumc.sasc.biopet.core.ToolCommand
object ExtractAlignedFastq extends ToolCommand { object ExtractAlignedFastq extends ToolCommand {
type FastqPair = (FastqRecord, FastqRecord) type FastqInput = (FastqRecord, Option[FastqRecord])
/** /**
* Function to create iterator over Interval given input interval string * Function to create iterator over Interval given input interval string
...@@ -74,7 +74,7 @@ object ExtractAlignedFastq extends ToolCommand { ...@@ -74,7 +74,7 @@ object ExtractAlignedFastq extends ToolCommand {
def makeMembershipFunction(iv: Iterator[Interval], def makeMembershipFunction(iv: Iterator[Interval],
inAln: File, inAln: File,
minMapQ: Int = 0, minMapQ: Int = 0,
commonSuffixLength: Int = 0): (FastqPair => Boolean) = { commonSuffixLength: Int = 0): (FastqInput => Boolean) = {
val inAlnReader = SamReaderFactory val inAlnReader = SamReaderFactory
.make() .make()
...@@ -112,54 +112,39 @@ object ExtractAlignedFastq extends ToolCommand { ...@@ -112,54 +112,39 @@ object ExtractAlignedFastq extends ToolCommand {
} }
) )
(pair: FastqPair) => pair._2 match { (pair: FastqInput) => pair._2 match {
case null => selected.contains(pair._1.getReadHeader) case None => selected.contains(pair._1.getReadHeader)
case otherwise => case Some(x) =>
require(commonSuffixLength < pair._1.getReadHeader.length) require(commonSuffixLength < pair._1.getReadHeader.length)
require(commonSuffixLength < pair._2.getReadHeader.length) require(commonSuffixLength < x.getReadHeader.length)
selected.contains(pair._1.getReadHeader.dropRight(commonSuffixLength)) selected.contains(pair._1.getReadHeader.dropRight(commonSuffixLength))
} }
} }
def selectFastqReads(memFunc: FastqPair => Boolean, def extractReads(memFunc: FastqInput => Boolean,
inputFastq1: FastqReader, inputFastq1: FastqReader, outputFastq1: BasicFastqWriter): Unit =
outputFastq1: BasicFastqWriter, inputFastq1.iterator.asScala
inputFastq2: FastqReader = null, .zip(Iterator.continually(None))
outputFastq2: BasicFastqWriter = null): Unit = {
val i1 = inputFastq1.iterator.asScala
val i2 = inputFastq2 match {
case null => Iterator.continually(null)
case otherwise => otherwise.iterator.asScala
}
val o1 = outputFastq1
val o2 = (inputFastq2, outputFastq2) match {
case (null, null) => null
case (_, null) => throw new IllegalArgumentException("Missing output FASTQ 2")
case (null, _) => throw new IllegalArgumentException("Output FASTQ 2 supplied but there is no input FASTQ 2")
case (x, y) => outputFastq2
}
logger.info("Writing output file(s) ...")
// zip, filter based on function, and write to output file(s)
i1.zip(i2)
.filter(rec => memFunc(rec._1, rec._2)) .filter(rec => memFunc(rec._1, rec._2))
.foreach { .foreach(rec => outputFastq1.write(rec._1))
case (rec1, null) =>
o1.write(rec1) def extractReads(memFunc: FastqInput => Boolean,
case (rec1, rec2) => inputFastq1: FastqReader, outputFastq1: BasicFastqWriter,
o1.write(rec1) inputFastq2: FastqReader, outputFastq2: BasicFastqWriter): Unit =
o2.write(rec2) inputFastq1.iterator.asScala
} .zip(inputFastq2.iterator.asScala)
.filter(rec => memFunc(rec._1, Some(rec._2)))
} .foreach(rec => {
outputFastq1.write(rec._1)
case class Args(inputBam: File = null, outputFastq2.write(rec._2)
})
case class Args(inputBam: File = new File(""),
intervals: List[String] = List.empty[String], intervals: List[String] = List.empty[String],
inputFastq1: File = null, inputFastq1: File = new File(""),
inputFastq2: File = null, inputFastq2: Option[File] = None,
outputFastq1: File = null, outputFastq1: File = new File(""),
outputFastq2: File = null, outputFastq2: Option[File] = None,
minMapQ: Int = 0, minMapQ: Int = 0,
commonSuffixLength: Int = 0) extends AbstractArgs commonSuffixLength: Int = 0) extends AbstractArgs
...@@ -188,7 +173,7 @@ object ExtractAlignedFastq extends ToolCommand { ...@@ -188,7 +173,7 @@ object ExtractAlignedFastq extends ToolCommand {
} text "Input FASTQ file 1" } text "Input FASTQ file 1"
opt[File]('j', "in2") optional () valueName "<fastq>" action { (x, c) => opt[File]('j', "in2") optional () valueName "<fastq>" action { (x, c) =>
c.copy(inputFastq1 = x) c.copy(inputFastq2 = Option(x))
} validate { } validate {
x => if (x.exists) success else failure("Input FASTQ file 2 not found") x => if (x.exists) success else failure("Input FASTQ file 2 not found")
} text "Input FASTQ file 2 (default: none)" } text "Input FASTQ file 2 (default: none)"
...@@ -198,7 +183,7 @@ object ExtractAlignedFastq extends ToolCommand { ...@@ -198,7 +183,7 @@ object ExtractAlignedFastq extends ToolCommand {
} text "Output FASTQ file 1" } text "Output FASTQ file 1"
opt[File]('p', "out2") optional () valueName "<fastq>" action { (x, c) => opt[File]('p', "out2") optional () valueName "<fastq>" action { (x, c) =>
c.copy(outputFastq1 = x) c.copy(outputFastq2 = Option(x))
} text "Output FASTQ file 2 (default: none)" } text "Output FASTQ file 2 (default: none)"
opt[Int]('Q', "min_mapq") optional () action { (x, c) => opt[Int]('Q', "min_mapq") optional () action { (x, c) =>
...@@ -215,35 +200,43 @@ object ExtractAlignedFastq extends ToolCommand { ...@@ -215,35 +200,43 @@ object ExtractAlignedFastq extends ToolCommand {
""".stripMargin) """.stripMargin)
checkConfig { c => checkConfig { c =>
if (!c.inputBam.exists) if (c.inputFastq2 != None && c.outputFastq2 == None)
failure("Input BAM file not found")
else if (!c.inputFastq1.exists)
failure("Input FASTQ file 1 not found")
else if (c.inputFastq2 != null && c.outputFastq2 == null)
failure("Missing output FASTQ file 2") failure("Missing output FASTQ file 2")
else if (c.inputFastq2 == null && c.outputFastq2 != null) else if (c.inputFastq2 == None && c.outputFastq2 != None)
failure("Missing input FASTQ file 2") failure("Missing input FASTQ file 2")
else else
success success
} }
} }
def main(args: Array[String]): Unit = { def parseArgs(args: Array[String]): Args =
new OptParser()
val commandArgs: Args = new OptParser()
.parse(args, Args()) .parse(args, Args())
.getOrElse(sys.exit(1)) .getOrElse(sys.exit(1))
def main(args: Array[String]): Unit = {
val commandArgs: Args = parseArgs(args)
val memFunc = makeMembershipFunction( val memFunc = makeMembershipFunction(
iv = makeIntervalFromString(commandArgs.intervals), iv = makeIntervalFromString(commandArgs.intervals),
inAln = commandArgs.inputBam, inAln = commandArgs.inputBam,
minMapQ = commandArgs.minMapQ, minMapQ = commandArgs.minMapQ,
commonSuffixLength = commandArgs.commonSuffixLength) commonSuffixLength = commandArgs.commonSuffixLength)
selectFastqReads(memFunc, (commandArgs.inputFastq2, commandArgs.outputFastq2) match {
inputFastq1 = new FastqReader(commandArgs.inputFastq1),
inputFastq2 = new FastqReader(commandArgs.inputFastq2), case (None, None) => extractReads(memFunc,
outputFastq1 = new BasicFastqWriter(commandArgs.outputFastq1), new FastqReader(commandArgs.inputFastq1),
outputFastq2 = new BasicFastqWriter(commandArgs.outputFastq2)) new BasicFastqWriter(commandArgs.inputFastq1))
case (Some(i2), Some(o2)) => extractReads(memFunc,
new FastqReader(commandArgs.inputFastq1),
new BasicFastqWriter(commandArgs.outputFastq1),
new FastqReader(i2),
new BasicFastqWriter(o2))
case _ => // handled by the command line config check above
}
} }
} }
...@@ -19,7 +19,7 @@ class LnUnitTest extends TestNGSuite with Matchers { ...@@ -19,7 +19,7 @@ class LnUnitTest extends TestNGSuite with Matchers {
ln.relative = true ln.relative = true
ln.in = new File("/dir/nested/target.txt") ln.in = new File("/dir/nested/target.txt")
ln.out = new File("/dir/nested/link.txt") ln.out = new File("/dir/nested/link.txt")
ln.cmd should ===("ln -s 'target.txt' '/dir/nested/link.txt'") ln.cmd should ===("ln -s target.txt /dir/nested/link.txt")
} }
@Test(description = "Target is one level above link, relative set to true") @Test(description = "Target is one level above link, relative set to true")
...@@ -28,7 +28,7 @@ class LnUnitTest extends TestNGSuite with Matchers { ...@@ -28,7 +28,7 @@ class LnUnitTest extends TestNGSuite with Matchers {
ln.relative = true ln.relative = true
ln.in = new File("/dir/target.txt") ln.in = new File("/dir/target.txt")
ln.out = new File("/dir/nested/link.txt") ln.out = new File("/dir/nested/link.txt")
ln.cmd should ===("ln -s '../target.txt' '/dir/nested/link.txt'") ln.cmd should ===("ln -s ../target.txt /dir/nested/link.txt")
} }
@Test(description = "Target is two levels above link, relative set to true") @Test(description = "Target is two levels above link, relative set to true")
...@@ -37,7 +37,7 @@ class LnUnitTest extends TestNGSuite with Matchers { ...@@ -37,7 +37,7 @@ class LnUnitTest extends TestNGSuite with Matchers {
ln.relative = true ln.relative = true
ln.in = new File("/target.txt") ln.in = new File("/target.txt")
ln.out = new File("/dir/nested/link.txt") ln.out = new File("/dir/nested/link.txt")
ln.cmd should ===("ln -s '../../target.txt' '/dir/nested/link.txt'") ln.cmd should ===("ln -s ../../target.txt /dir/nested/link.txt")
} }
@Test(description = "Target is a child of a directory one level above link, relative set to true") @Test(description = "Target is a child of a directory one level above link, relative set to true")
...@@ -46,7 +46,7 @@ class LnUnitTest extends TestNGSuite with Matchers { ...@@ -46,7 +46,7 @@ class LnUnitTest extends TestNGSuite with Matchers {
ln.relative = true ln.relative = true
ln.in = new File("/dir/another_nested/target.txt") ln.in = new File("/dir/another_nested/target.txt")
ln.out = new File("/dir/nested/link.txt") ln.out = new File("/dir/nested/link.txt")
ln.cmd should ===("ln -s '../another_nested/target.txt' '/dir/nested/link.txt'") ln.cmd should ===("ln -s ../another_nested/target.txt /dir/nested/link.txt")
} }
@Test(description = "Target is one level below link, relative set to true") @Test(description = "Target is one level below link, relative set to true")
...@@ -55,7 +55,7 @@ class LnUnitTest extends TestNGSuite with Matchers { ...@@ -55,7 +55,7 @@ class LnUnitTest extends TestNGSuite with Matchers {
ln.relative = true ln.relative = true
ln.in = new File("/dir/nested/deeper/target.txt") ln.in = new File("/dir/nested/deeper/target.txt")
ln.out = new File("/dir/nested/link.txt") ln.out = new File("/dir/nested/link.txt")
ln.cmd should ===("ln -s 'deeper/target.txt' '/dir/nested/link.txt'") ln.cmd should ===("ln -s deeper/target.txt /dir/nested/link.txt")
} }
@Test(description = "Target is two levels below link, relative set to true") @Test(description = "Target is two levels below link, relative set to true")
...@@ -64,7 +64,7 @@ class LnUnitTest extends TestNGSuite with Matchers { ...@@ -64,7 +64,7 @@ class LnUnitTest extends TestNGSuite with Matchers {
ln.relative = true ln.relative = true
ln.in = new File("/dir/nested/even/deeper/target.txt") ln.in = new File("/dir/nested/even/deeper/target.txt")
ln.out = new File("/dir/nested/link.txt") ln.out = new File("/dir/nested/link.txt")
ln.cmd should ===("ln -s 'even/deeper/target.txt' '/dir/nested/link.txt'") ln.cmd should ===("ln -s even/deeper/target.txt /dir/nested/link.txt")
} }
@Test(description = "Relative set to false") @Test(description = "Relative set to false")
...@@ -73,7 +73,7 @@ class LnUnitTest extends TestNGSuite with Matchers { ...@@ -73,7 +73,7 @@ class LnUnitTest extends TestNGSuite with Matchers {
ln.relative = false ln.relative = false
ln.in = new File("/dir/nested/target.txt") ln.in = new File("/dir/nested/target.txt")
ln.out = new File("/dir/nested/link.txt") ln.out = new File("/dir/nested/link.txt")
ln.cmd should ===("ln -s '/dir/nested/target.txt' '/dir/nested/link.txt'") ln.cmd should ===("ln -s /dir/nested/target.txt /dir/nested/link.txt")
} }
// TODO: test for case where abosolute is true and input paths are relative? // TODO: test for case where abosolute is true and input paths are relative?
......
...@@ -8,7 +8,7 @@ import java.io.File ...@@ -8,7 +8,7 @@ import java.io.File
import java.nio.file.Paths import java.nio.file.Paths
import org.mockito.Matchers._ import org.mockito.Matchers._
import org.mockito.Mockito._ import org.mockito.Mockito.{ inOrder => inOrd, times, verify }
import org.scalatest.Matchers import org.scalatest.Matchers
import org.scalatest.mock.MockitoSugar import org.scalatest.mock.MockitoSugar
import org.scalatest.testng.TestNGSuite import org.scalatest.testng.TestNGSuite
...@@ -22,7 +22,10 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat ...@@ -22,7 +22,10 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat
import ExtractAlignedFastq._ import ExtractAlignedFastq._
private def resourceFile(p: String): File = private def resourceFile(p: String): File =
new File(Paths.get(getClass.getResource(p).toURI).toString) new File(resourcePath(p))
private def resourcePath(p: String): String =
Paths.get(getClass.getResource(p).toURI).toString
private def makeInterval(chr: String, start: Int, end: Int): Interval = private def makeInterval(chr: String, start: Int, end: Int): Interval =
new Interval(chr, start, end) new Interval(chr, start, end)
...@@ -30,11 +33,11 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat ...@@ -30,11 +33,11 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat
private def makeRecord(header: String): FastqRecord = private def makeRecord(header: String): FastqRecord =
new FastqRecord(header, "ATGC", "", "HIHI") new FastqRecord(header, "ATGC", "", "HIHI")
private def makeSingleRecords(headers: String*): Map[String, FastqPair] = private def makeSingleRecords(headers: String*): Map[String, FastqInput] =
headers.map(x => (x, (makeRecord(x), null))).toMap headers.map(x => (x, (makeRecord(x), None))).toMap
private def makePairRecords(headers: (String, (String, String))*): Map[String, FastqPair] = private def makePairRecords(headers: (String, (String, String))*): Map[String, FastqInput] =
headers.map(x => (x._1, (makeRecord(x._2._1), makeRecord(x._2._2)))).toMap headers.map(x => (x._1, (makeRecord(x._2._1), Some(makeRecord(x._2._2))))).toMap
private def makeClue(tName: String, f: File, rName: String): String = private def makeClue(tName: String, f: File, rName: String): String =
tName + " on " + f.getName + ", read " + rName + ": " tName + " on " + f.getName + ", read " + rName + ": "
...@@ -109,7 +112,7 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat ...@@ -109,7 +112,7 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat
@Test(dataProvider = "singleAlnProvider1") @Test(dataProvider = "singleAlnProvider1")
def testSingleBamDefault(name: String, feat: Interval, inAln: File, def testSingleBamDefault(name: String, feat: Interval, inAln: File,
fastqMap: Map[String, FastqPair], resultMap: Map[String, Boolean]) = { fastqMap: Map[String, FastqInput], resultMap: Map[String, Boolean]) = {
require(resultMap.keySet == fastqMap.keySet) require(resultMap.keySet == fastqMap.keySet)
val memFunc = makeMembershipFunction(Iterator(feat), inAln) val memFunc = makeMembershipFunction(Iterator(feat), inAln)
for ((key, (rec1, rec2)) <- fastqMap) { for ((key, (rec1, rec2)) <- fastqMap) {
...@@ -137,7 +140,7 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat ...@@ -137,7 +140,7 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat
@Test(dataProvider = "singleAlnProvider2") @Test(dataProvider = "singleAlnProvider2")
def testSingleBamMinMapQ(name: String, feat: Interval, inAln: File, minMapQ: Int, def testSingleBamMinMapQ(name: String, feat: Interval, inAln: File, minMapQ: Int,
fastqMap: Map[String, FastqPair], resultMap: Map[String, Boolean]) = { fastqMap: Map[String, FastqInput], resultMap: Map[String, Boolean]) = {
require(resultMap.keySet == fastqMap.keySet) require(resultMap.keySet == fastqMap.keySet)
val memFunc = makeMembershipFunction(Iterator(feat), inAln, minMapQ) val memFunc = makeMembershipFunction(Iterator(feat), inAln, minMapQ)
for ((key, (rec1, rec2)) <- fastqMap) { for ((key, (rec1, rec2)) <- fastqMap) {
...@@ -175,7 +178,7 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat ...@@ -175,7 +178,7 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat
@Test(dataProvider = "pairAlnProvider1") @Test(dataProvider = "pairAlnProvider1")
def testPairBamDefault(name: String, feat: Interval, inAln: File, def testPairBamDefault(name: String, feat: Interval, inAln: File,
fastqMap: Map[String, FastqPair], resultMap: Map[String, Boolean]) = { fastqMap: Map[String, FastqInput], resultMap: Map[String, Boolean]) = {
require(resultMap.keySet == fastqMap.keySet) require(resultMap.keySet == fastqMap.keySet)
val memFunc = makeMembershipFunction(Iterator(feat), inAln, commonSuffixLength = 2) val memFunc = makeMembershipFunction(Iterator(feat), inAln, commonSuffixLength = 2)
for ((key, (rec1, rec2)) <- fastqMap) { for ((key, (rec1, rec2)) <- fastqMap) {
...@@ -185,53 +188,68 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat ...@@ -185,53 +188,68 @@ class ExtractAlignedFastqUnitTest extends TestNGSuite with MockitoSugar with Mat
} }
} }
@Test def testWriteSingleBamDefault() = { @Test def testWriteSingleFastqDefault() = {
val memFunc = (recs: FastqPair) => Set("r01", "r03").contains(recs._1.getReadHeader) val memFunc = (recs: FastqInput) => Set("r01", "r03").contains(recs._1.getReadHeader)
val in1 = new FastqReader(resourceFile("/single01.fq")) val in1 = new FastqReader(resourceFile("/single01.fq"))
val mo1 = mock[BasicFastqWriter] val mo1 = mock[BasicFastqWriter]
selectFastqReads(memFunc, in1, mo1) val obs = inOrd(mo1)
extractReads(memFunc, in1, mo1)
verify(mo1, times(2)).write(anyObject.asInstanceOf[FastqRecord]) verify(mo1, times(2)).write(anyObject.asInstanceOf[FastqRecord])
verify(mo1).write(new FastqRecord("r01", "A", "", "H")) obs.verify(mo1).write(new FastqRecord("r01", "A", "", "H"))
verify(mo1).write(new FastqRecord("r03", "G", "", "H")) obs.verify(mo1).write(new FastqRecord("r03", "G", "", "H"))
} }
@Test def testWritePairBamDefault() = { @Test def testWritePairFastqDefault() = {
val memFunc = (recs: FastqPair) => Set("r01/1", "r01/2", "r03/1", "r03/2").contains(recs._1.getReadHeader) val mockSet = Set("r01/1", "r01/2", "r03/1", "r03/2")
val memFunc = (recs: FastqInput) => mockSet.contains(recs._1.getReadHeader) || mockSet.contains(recs._2.get.getReadHeader)
val in1 = new FastqReader(resourceFile("/paired01a.fq")) val in1 = new FastqReader(resourceFile("/paired01a.fq"))
val in2 = new FastqReader(resourceFile("/paired01b.fq")) val in2 = new FastqReader(resourceFile("/paired01b.fq"))
val mo1 = mock[BasicFastqWriter] val mo1 = mock[BasicFastqWriter]
val mo2 = mock[BasicFastqWriter] val mo2 = mock[BasicFastqWriter]
selectFastqReads(memFunc, in1, mo1, in2, mo2) val obs = inOrd(mo1, mo2)
extractReads(memFunc, in1, mo1, in2, mo2)
obs.verify(mo1).write(new FastqRecord("r01/1", "A", "", "H"))
obs.verify(mo2).write(new FastqRecord("r01/2", "T", "", "I"))
obs.verify(mo1).write(new FastqRecord("r03/1", "G", "", "H"))
obs.verify(mo2).write(new FastqRecord("r03/2", "C", "", "I"))
verify(mo1, times(2)).write(anyObject.asInstanceOf[FastqRecord]) verify(mo1, times(2)).write(anyObject.asInstanceOf[FastqRecord])
verify(mo1).write(new FastqRecord("r01/1", "A", "", "H"))
verify(mo1).write(new FastqRecord("r03/1", "G", "", "H"))
verify(mo2, times(2)).write(anyObject.asInstanceOf[FastqRecord]) verify(mo2, times(2)).write(anyObject.asInstanceOf[FastqRecord])
verify(mo2).write(new FastqRecord("r01/2", "T", "", "I"))
verify(mo2).write(new FastqRecord("r03/2", "C", "", "I"))
}
@Test def testWriteNoOutputFastq2() = {
val memFunc: (FastqPair => Boolean) = (recs) => true
val in1 = mock[FastqReader]
val in2 = mock[FastqReader]
val out1 = mock[BasicFastqWriter]
val thrown = intercept[IllegalArgumentException] {
selectFastqReads(memFunc, in1, out1, in2)
}
thrown.getMessage should ===("Missing output FASTQ 2")
verify(out1, never).write(anyObject.asInstanceOf[FastqRecord])
} }
@Test def testWriteNoInputFastq2() = { @Test def testArgsMinimum() = {
val memFunc: (FastqPair => Boolean) = (recs) => true val args = Array(
val in1 = mock[FastqReader] "-I", resourcePath("/single01.bam"),
val out1 = mock[BasicFastqWriter] "--interval", "chrQ:1-400",
val out2 = mock[BasicFastqWriter] "-i", resourcePath("/single01.fq"),
val thrown = intercept[IllegalArgumentException] { "-o", "/tmp/tm1.fq"
selectFastqReads(memFunc, in1, out1, outputFastq2 = out2) )
} val parsed = parseArgs(args)
thrown.getMessage should ===("Output FASTQ 2 supplied but there is no input FASTQ 2") parsed.inputBam shouldBe resourceFile("/single01.bam")
verify(out1, never).write(anyObject.asInstanceOf[FastqRecord]) parsed.intervals shouldBe List("chrQ:1-400")
verify(out2, never).write(anyObject.asInstanceOf[FastqRecord]) parsed.inputFastq1 shouldBe resourceFile("/single01.fq")
parsed.outputFastq1 shouldBe new File("/tmp/tm1.fq")
}
@Test def testArgsMaximum() = {
val args = Array(
"-I", resourcePath("/paired01.bam"),
"--interval", "chrQ:1-400",
"--interval", "chrP:1000-4000",
"-i", resourcePath("/paired01a.fq"),
"-j", resourcePath("/paired01b.fq"),
"-o", "/tmp/tm1.fq",
"-p", "/tmp/tm2.fq",
"-s", "2",
"-Q", "30"
)
val parsed = parseArgs(args)
parsed.inputBam shouldBe resourceFile("/paired01.bam")
parsed.intervals shouldBe List("chrQ:1-400", "chrP:1000-4000")
parsed.inputFastq1 shouldBe resourceFile("/paired01a.fq")
parsed.inputFastq2.get shouldBe resourceFile("/paired01b.fq")
parsed.outputFastq1 shouldBe new File("/tmp/tm1.fq")
parsed.outputFastq2.get shouldBe new File("/tmp/tm2.fq")
parsed.commonSuffixLength shouldBe 2
parsed.minMapQ shouldBe 30
} }
} }
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<modelVersion>4.0.0</modelVersion> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<groupId>nl.lumc.sasc</groupId> <modelVersion>4.0.0</modelVersion>
<artifactId>Biopet</artifactId> <groupId>nl.lumc.sasc</groupId>
<version>0.1.3</version> <artifactId>Biopet</artifactId>
<packaging>pom</packaging> <version>0.2.0-DEV</version>
<name>Biopet</name> <packaging>pom</packaging>
<modules> <name>Biopet</name>
<module>biopet-framework</module> <modules>
</modules> <module>biopet-framework</module>
</modules>
</project> </project>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment