This is my second day in learning Scala and I still need to develop a taste of functional programming, I often find myself doing imperative coding. Below is the result of my TDD practice.
Code
class DNA(dnaSequence: String) {
var count = collection.mutable.Map('A' -> 0, 'T' -> 0, 'C' -> 0, 'G' -> 0)
dnaSequence.foreach { (i: Char) =>
validate(i)
count = count.updated(i, count.get(i).getOrElse(0) + 1)
}
def nucleotideCounts() = count
def nucleotideCounts(nucleotide: Char) = {
validate(nucleotide)
count.get(nucleotide).getOrElse(0)
}
private def validate(chr: Char) = {
if (!count.contains(chr)) throw new RuntimeException()
}
}
Test Suite
import org.scalatest._
class NucleotideCountSpecs extends FlatSpec with Matchers {
"empty dna string" should "have no adenine" in {
new DNA("").nucleotideCounts('A') should be (0)
}
it should "have no nucleotides" in {
val expected = Map('A' -> 0, 'T' -> 0, 'C' -> 0, 'G' -> 0)
new DNA("").nucleotideCounts should be (expected)
}
"a repetitive sequence" should "count cytosine" in {
new DNA("CCCCC").nucleotideCounts('C') should be (5)
}
it should "have only guanine" in {
val expected = Map('A' -> 0, 'T' -> 0, 'C' -> 0, 'G' -> 8)
new DNA("GGGGGGGG").nucleotideCounts should be (expected)
}
"a mixed dna string" should "count only thymine" in {
new DNA("GGGGGTAACCCGG").nucleotideCounts('T') should be (1)
}
it should "count a nucleotide only once" in {
val dna = new DNA("CGATTGGG")
dna.nucleotideCounts('T')
dna.nucleotideCounts('T') should be (2)
}
it should "not change counts after counting adenine" in {
val dna = new DNA("GATTACA")
dna.nucleotideCounts('A')
val expected = Map('A' -> 3, 'T' -> 2, 'C' -> 1, 'G' -> 1)
dna.nucleotideCounts should be (expected)
}
it should "validate nucleotides" in {
a [RuntimeException] should be thrownBy new DNA("GACT").nucleotideCounts('X')
}
it should "validate dna not rna" in {
a [RuntimeException] should be thrownBy new DNA("ACGU")
}
it should "validate dna" in {
a [RuntimeException] should be thrownBy new DNA("John")
}
it should "count all nucleotides" in {
val s = "AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC"
val dna = new DNA(s)
val expected = Map('A' -> 20, 'T' -> 21, 'G' -> 17, 'C' -> 12)
dna.nucleotideCounts should be (expected)
}
}