VcfStatsTest.scala 8.95 KB
Newer Older
bow's avatar
bow committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * Biopet is built on top of GATK Queue for building bioinformatic
 * pipelines. It is mainly intended to support LUMC SHARK cluster which is running
 * SGE. But other types of HPC that are supported by GATK Queue (such as PBS)
 * should also be able to execute Biopet tools and pipelines.
 *
 * Copyright 2014 Sequencing Analysis Support Core - Leiden University Medical Center
 *
 * Contact us at: sasc@lumc.nl
 *
 * A dual licensing mode is applied. The source code within this project that are
 * not part of GATK Queue is freely available for non-commercial use under an AGPL
 * license; For commercial users or users who do not want to follow the AGPL
 * license, please contact us to obtain a separate license.
 */
Peter van 't Hof's avatar
Peter van 't Hof committed
16
17
package nl.lumc.sasc.biopet.tools

Sander Bollen's avatar
Sander Bollen committed
18
19
20
import java.io.File
import java.nio.file.{Files, Paths}

21
import htsjdk.variant.variantcontext.Allele
Peter van 't Hof's avatar
Peter van 't Hof committed
22
import nl.lumc.sasc.biopet.tools.VcfStats._
Peter van 't Hof's avatar
Peter van 't Hof committed
23
24
25
import org.scalatest.Matchers
import org.scalatest.testng.TestNGSuite
import org.testng.annotations.Test
Peter van 't Hof's avatar
Peter van 't Hof committed
26

Peter van 't Hof's avatar
Peter van 't Hof committed
27
28
29
import scala.collection.mutable

/**
Peter van 't Hof's avatar
Peter van 't Hof committed
30
31
 * Test class for [[VcfStats]]
 *
Peter van 't Hof's avatar
Peter van 't Hof committed
32
33
34
 * Created by pjvan_thof on 2/5/15.
 */
class VcfStatsTest extends TestNGSuite with Matchers {
Sander Bollen's avatar
Sander Bollen committed
35
36
37
38
  private def resourcePath(p: String): String = {
    Paths.get(getClass.getResource(p).toURI).toString
  }

Peter van 't Hof's avatar
Peter van 't Hof committed
39
40

  @Test
Peter van 't Hof's avatar
Peter van 't Hof committed
41
  def testSampleToSampleStats(): Unit = {
Peter van 't Hof's avatar
Peter van 't Hof committed
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    val s1 = SampleToSampleStats()
    val s2 = SampleToSampleStats()
    s1.alleleOverlap shouldBe 0
    s1.genotypeOverlap shouldBe 0
    s2.alleleOverlap shouldBe 0
    s2.genotypeOverlap shouldBe 0

    s1 += s2
    s1.alleleOverlap shouldBe 0
    s1.genotypeOverlap shouldBe 0
    s2.alleleOverlap shouldBe 0
    s2.genotypeOverlap shouldBe 0

    s2.alleleOverlap = 2
    s2.genotypeOverlap = 3

    s1 += s2
    s1.alleleOverlap shouldBe 2
    s1.genotypeOverlap shouldBe 3
    s2.alleleOverlap shouldBe 2
    s2.genotypeOverlap shouldBe 3

    s1 += s2
    s1.alleleOverlap shouldBe 4
    s1.genotypeOverlap shouldBe 6
    s2.alleleOverlap shouldBe 2
    s2.genotypeOverlap shouldBe 3
  }

  @Test
Peter van 't Hof's avatar
Peter van 't Hof committed
72
  def testSampleStats(): Unit = {
Peter van 't Hof's avatar
Peter van 't Hof committed
73
74
75
76
77
78
79
80
81
82
83
    val s1 = SampleStats()
    val s2 = SampleStats()

    s1.sampleToSample += "s1" -> SampleToSampleStats()
    s1.sampleToSample += "s2" -> SampleToSampleStats()
    s2.sampleToSample += "s1" -> SampleToSampleStats()
    s2.sampleToSample += "s2" -> SampleToSampleStats()

    s1.sampleToSample("s1").alleleOverlap = 1
    s2.sampleToSample("s2").alleleOverlap = 2

Peter van 't Hof's avatar
Peter van 't Hof committed
84
85
86
87
    val bla1 = s1.genotypeStats.getOrElse("chr", mutable.Map[String, mutable.Map[Any, Int]]()) += "1" -> mutable.Map(1 -> 1)
    s1.genotypeStats += "chr" -> bla1
    val bla2 = s2.genotypeStats.getOrElse("chr", mutable.Map[String, mutable.Map[Any, Int]]()) += "2" -> mutable.Map(2 -> 2)
    s2.genotypeStats += "chr" -> bla2
Peter van 't Hof's avatar
Peter van 't Hof committed
88
89
90
91
92

    val ss1 = SampleToSampleStats()
    val ss2 = SampleToSampleStats()

    s1 += s2
Peter van 't Hof's avatar
Peter van 't Hof committed
93
    s1.genotypeStats.getOrElse("chr", mutable.Map[String, mutable.Map[Any, Int]]()) shouldBe mutable.Map("1" -> mutable.Map(1 -> 1), "2" -> mutable.Map(2 -> 2))
Peter van 't Hof's avatar
Peter van 't Hof committed
94
95
96
97
98
    ss1.alleleOverlap = 1
    ss2.alleleOverlap = 2
    s1.sampleToSample shouldBe mutable.Map("s1" -> ss1, "s2" -> ss2)

    s1 += s2
Peter van 't Hof's avatar
Peter van 't Hof committed
99
    s1.genotypeStats.getOrElse("chr", mutable.Map[String, mutable.Map[Any, Int]]()) shouldBe mutable.Map("1" -> mutable.Map(1 -> 1), "2" -> mutable.Map(2 -> 4))
Peter van 't Hof's avatar
Peter van 't Hof committed
100
101

    s1 += s1
Peter van 't Hof's avatar
Peter van 't Hof committed
102
    s1.genotypeStats.getOrElse("chr", mutable.Map[String, mutable.Map[Any, Int]]()) shouldBe mutable.Map("1" -> mutable.Map(1 -> 2), "2" -> mutable.Map(2 -> 8))
Peter van 't Hof's avatar
Peter van 't Hof committed
103
  }
104
105

  @Test
Peter van 't Hof's avatar
Peter van 't Hof committed
106
  def testAlleleOverlap(): Unit = {
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

    val a1 = Allele.create("G")
    val a2 = Allele.create("A")

    alleleOverlap(List(a1, a1), List(a1, a1)) shouldBe 2
    alleleOverlap(List(a2, a2), List(a2, a2)) shouldBe 2
    alleleOverlap(List(a1, a2), List(a1, a2)) shouldBe 2
    alleleOverlap(List(a1, a2), List(a2, a1)) shouldBe 2
    alleleOverlap(List(a2, a1), List(a1, a2)) shouldBe 2
    alleleOverlap(List(a2, a1), List(a2, a1)) shouldBe 2

    alleleOverlap(List(a1, a2), List(a1, a1)) shouldBe 1
    alleleOverlap(List(a2, a1), List(a1, a1)) shouldBe 1
    alleleOverlap(List(a1, a1), List(a1, a2)) shouldBe 1
    alleleOverlap(List(a1, a1), List(a2, a1)) shouldBe 1

    alleleOverlap(List(a1, a1), List(a2, a2)) shouldBe 0
    alleleOverlap(List(a2, a2), List(a1, a1)) shouldBe 0
  }
Sander Bollen's avatar
Sander Bollen committed
126
127
128

  @Test
  def testMergeStatsMap = {
Sander Bollen's avatar
Sander Bollen committed
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
    val m1 : mutable.Map[Any, Int] = mutable.Map("a" -> 1)
    val m2 : mutable.Map[Any, Int] = mutable.Map("b" -> 2)

    mergeStatsMap(m1, m2)

    m1 should equal (mutable.Map("a" -> 1, "b" -> 2))

    val m3 : mutable.Map[Any, Int] = mutable.Map(1 -> 500)
    val m4 : mutable.Map[Any, Int] = mutable.Map(6 -> 125)

    mergeStatsMap(m3, m4)

    m3 should equal (mutable.Map(1 -> 500, 6 -> 125))

    mergeStatsMap(m1, m3)

    m1 should equal (mutable.Map("a" -> 1, "b" -> 2, 1 -> 500, 6 -> 125))
Sander Bollen's avatar
Sander Bollen committed
146
147
148
149
  }

  @Test
  def testMergeNestedStatsMap = {
Sander Bollen's avatar
Sander Bollen committed
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    val m1 : mutable.Map[String, mutable.Map[String, mutable.Map[Any, Int]]] = mutable.Map("test" ->
      mutable.Map("nested" -> mutable.Map("a" -> 1)))
    val m2: Map[String, Map[String, Map[Any, Int]]] = Map("test" ->
      Map("nested" -> Map("b" -> 2)))

    mergeNestedStatsMap(m1, m2)

    m1 should equal (mutable.Map("test" -> mutable.Map("nested" -> mutable.Map("a" -> 1, "b" -> 2))))

    val m3 : mutable.Map[String, mutable.Map[String, mutable.Map[Any, Int]]] = mutable.Map("test" ->
      mutable.Map("nestedd" -> mutable.Map(1 -> 500)))
    val m4: Map[String, Map[String, Map[Any, Int]]] = Map("test" ->
      Map("nestedd" -> Map(6 -> 125)))

    mergeNestedStatsMap(m3, m4)

    m3 should equal (mutable.Map("test" -> mutable.Map("nestedd" -> mutable.Map(1 -> 500, 6 -> 125))))

    val m5 = m3.toMap.map(x => x._1 -> x._2.toMap.map(y => y._1 -> y._2.toMap))

    mergeNestedStatsMap(m1, m5)

    m1 should equal (mutable.Map("test" -> mutable.Map("nested" -> mutable.Map("a" -> 1, "b" -> 2),
    "nestedd" -> mutable.Map(1 -> 500, 6 -> 125))))
Sander Bollen's avatar
Sander Bollen committed
174
175
176
177
  }

  @Test
  def testValueOfTsv = {
Sander Bollen's avatar
Sander Bollen committed
178
179
180
181
182
183
184
    val i = new File(resourcePath("/sample.tsv"))

    valueFromTsv(i, "Sample_ID_1", "library") should be (Some("Lib_ID_1"))
    valueFromTsv(i, "Sample_ID_2", "library") should be (Some("Lib_ID_2"))
    valueFromTsv(i, "Sample_ID_1", "bam") should be (Some("MyFirst.bam"))
    valueFromTsv(i, "Sample_ID_2", "bam") should be (Some("MySecond.bam"))
    valueFromTsv(i, "Sample_ID_3", "bam") should be (empty)
Sander Bollen's avatar
Sander Bollen committed
185
186
187
188
  }

  @Test
  def testMain = {
Sander Bollen's avatar
Sander Bollen committed
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
    val tmp = Files.createTempDirectory("vcfStats")
    val vcf = resourcePath("/chrQ.vcf.gz")
    val ref = resourcePath("/fake_chrQ.fa")

    noException should be thrownBy main(Array("-I", vcf, "-R", ref, "-o", tmp.toAbsolutePath.toString))
    noException should be thrownBy main(Array("-I", vcf, "-R", ref, "-o", tmp.toAbsolutePath.toString, "--allInfoTags"))
    noException should be thrownBy main(Array("-I", vcf, "-R", ref, "-o",
      tmp.toAbsolutePath.toString, "--allInfoTags", "--allGenotypeTags"))
    noException should be thrownBy main(Array("-I", vcf, "-R", ref, "-o",
      tmp.toAbsolutePath.toString, "--binSize", "50", "--writeBinStats"))
    noException should be thrownBy main(Array("-I", vcf, "-R", ref, "-o",
      tmp.toAbsolutePath.toString, "--binSize", "50", "--writeBinStats",
      "--generalWiggle", "Total"))
    noException should be thrownBy main(Array("-I", vcf, "-R", ref, "-o",
      tmp.toAbsolutePath.toString, "--binSize", "50", "--writeBinStats",
      "--genotypeWiggle", "Total"))

    val genotypes = List("Het", "HetNonRef", "Hom", "HomRef", "HomVar", "Mixed", "NoCall", "NonInformative",
      "Available", "Called", "Filtered", "Variant")

    genotypes.foreach(
      x => noException should be thrownBy main(Array("-I", vcf, "-R", ref, "-o",
        tmp.toAbsolutePath.toString, "--binSize", "50", "--writeBinStats",
        "--genotypeWiggle", x))
    )

    val general = List("Biallelic", "ComplexIndel", "Filtered", "FullyDecoded", "Indel", "Mixed",
      "MNP", "MonomorphicInSamples", "NotFiltered", "PointEvent", "PolymorphicInSamples",
      "SimpleDeletion", "SimpleInsertion", "SNP", "StructuralIndel", "Symbolic",
      "SymbolicOrSV", "Variant")

    general.foreach(
      x => noException should be thrownBy main(Array("-I", vcf, "-R", ref, "-o",
        tmp.toAbsolutePath.toString, "--binSize", "50", "--writeBinStats",
        "--generalWiggle", x))
    )
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242


    // returns null when validation fails
    def validateArgs(array: Array[String]): Option[Args] = {
      val argsParser = new OptParser
      argsParser.parse(array, Args())
    }

    validateArgs(Array("-I", vcf, "-R", ref, "-o",
      tmp.toAbsolutePath.toString, "--binSize", "50", "--writeBinStats",
      "--genotypeWiggle", "NonexistentThing")) shouldBe empty

    validateArgs(Array("-I", vcf, "-R", ref, "-o",
      tmp.toAbsolutePath.toString, "--binSize", "50", "--writeBinStats",
      "--generalWiggle", "NonexistentThing")) shouldBe empty

    validateArgs(Array("-R", ref, "-o",
      tmp.toAbsolutePath.toString)) shouldBe empty
Sander Bollen's avatar
Sander Bollen committed
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  }

  @Test
  def testSortAnyAny = {
    //stub
  }

  @Test
  def testCheckGeneral = {
    //stub
  }

  @Test
  def testCheckGenotype = {
    //stub
  }
Peter van 't Hof's avatar
Peter van 't Hof committed
259
}