aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorvlad <vlad@drivergrp.com>2016-07-19 15:01:30 -0400
committervlad <vlad@drivergrp.com>2016-07-19 15:01:30 -0400
commit979ff9e765e3c08501cbd00354a87013853fe796 (patch)
treec5d41ed99759c3bf97ba4ef9162aeb68ed4c29f8 /src/test
parent8d45c2ec5e8abc63046c610109471cc3fa7bfaa2 (diff)
downloaddriver-core-979ff9e765e3c08501cbd00354a87013853fe796.tar.gz
driver-core-979ff9e765e3c08501cbd00354a87013853fe796.tar.bz2
driver-core-979ff9e765e3c08501cbd00354a87013853fe796.zip
Unit tests for core code and bug fixes
Diffstat (limited to 'src/test')
-rw-r--r--src/test/scala/com/drivergrp/core/CoreTest.scala30
-rw-r--r--src/test/scala/com/drivergrp/core/GeneratorsTest.scala206
-rw-r--r--src/test/scala/com/drivergrp/core/MessagesTest.scala80
-rw-r--r--src/test/scala/com/drivergrp/core/RestTest.scala40
-rw-r--r--src/test/scala/com/drivergrp/core/StatsTest.scala43
-rw-r--r--src/test/scala/com/drivergrp/core/TimeTest.scala57
6 files changed, 456 insertions, 0 deletions
diff --git a/src/test/scala/com/drivergrp/core/CoreTest.scala b/src/test/scala/com/drivergrp/core/CoreTest.scala
new file mode 100644
index 0000000..005cda5
--- /dev/null
+++ b/src/test/scala/com/drivergrp/core/CoreTest.scala
@@ -0,0 +1,30 @@
+package com.drivergrp.core
+
+import java.io.ByteArrayOutputStream
+
+import org.scalatest.mock.MockitoSugar
+import org.scalatest.{FlatSpec, Matchers}
+import org.mockito.Mockito._
+
+class CoreTest extends FlatSpec with Matchers with MockitoSugar {
+
+ "'make' function" should "allow initialization for objects" in {
+
+ val createdAndInitializedValue = make(new ByteArrayOutputStream(128)) { baos =>
+ baos.write(Array(1.toByte, 1.toByte, 0.toByte))
+ }
+
+ createdAndInitializedValue.toByteArray should be(Array(1.toByte, 1.toByte, 0.toByte))
+ }
+
+ "'using' function" should "call close after performing action on resource" in {
+
+ val baos = mock[ByteArrayOutputStream]
+
+ using(baos /* usually new ByteArrayOutputStream(128) */ ) { baos =>
+ baos.write(Array(1.toByte, 1.toByte, 0.toByte))
+ }
+
+ verify(baos).close()
+ }
+}
diff --git a/src/test/scala/com/drivergrp/core/GeneratorsTest.scala b/src/test/scala/com/drivergrp/core/GeneratorsTest.scala
new file mode 100644
index 0000000..9332e7f
--- /dev/null
+++ b/src/test/scala/com/drivergrp/core/GeneratorsTest.scala
@@ -0,0 +1,206 @@
+package com.drivergrp.core
+
+import org.scalatest.{Assertions, FlatSpec, Matchers}
+
+class GeneratorsTest extends FlatSpec with Matchers with Assertions {
+ import generators._
+
+ "Generators" should "be able to generate com.drivergrp.core.Id identifiers" in {
+
+ val generatedId1 = nextId[String]()
+ val generatedId2 = nextId[String]()
+ val generatedId3 = nextId[Long]()
+
+ generatedId1 should be >= 0L
+ generatedId2 should be >= 0L
+ generatedId3 should be >= 0L
+ generatedId1 should not be generatedId2
+ generatedId2 should !==(generatedId3)
+ }
+
+ it should "be able to generate com.drivergrp.core.Name names" in {
+
+ nextName[String]() should not be nextName[String]()
+ nextName[String]().length should be >= 0
+
+ val fixedLengthName = nextName[String](10)
+ fixedLengthName.length should be <= 10
+ assert(!fixedLengthName.exists(_.isControl))
+ }
+
+ it should "be able to generate strings" in {
+
+ nextString() should not be nextString()
+ nextString().length should be >= 0
+
+ val fixedLengthString = nextString(20)
+ fixedLengthString.length should be <= 20
+ assert(!fixedLengthString.exists(_.isControl))
+ }
+
+ it should "be able to generate options which are sometimes have values and sometimes not" in {
+
+ val generatedOption = nextOption("2")
+
+ generatedOption should not contain "1"
+ assert(generatedOption === Some("2") || generatedOption === None)
+ }
+
+ it should "be able to generate a pair of two generated values" in {
+
+ val constantPair = nextPair("foo", 1L)
+ constantPair._1 should be("foo")
+ constantPair._2 should be(1L)
+
+ val generatedPair = nextPair(nextId[Int](), nextName[Int]())
+
+ generatedPair._1 should be > 0L
+ generatedPair._2.length should be > 0
+
+ nextPair(nextId[Int](), nextName[Int]()) should not be
+ nextPair(nextId[Int](), nextName[Int]())
+ }
+
+ it should "be able to generate a triad of two generated values" in {
+
+ val constantTriad = nextTriad("foo", "bar", 1L)
+ constantTriad._1 should be("foo")
+ constantTriad._2 should be("bar")
+ constantTriad._3 should be(1L)
+
+ val generatedTriad = nextTriad(nextId[Int](), nextName[Int](), nextBigDecimal())
+
+ generatedTriad._1 should be > 0L
+ generatedTriad._2.length should be > 0
+ generatedTriad._3 should be >= BigDecimal(0.00)
+
+ nextTriad(nextId[Int](), nextName[Int](), nextBigDecimal()) should not be
+ nextTriad(nextId[Int](), nextName[Int](), nextBigDecimal())
+ }
+
+ it should "be able to generate a time value" in {
+
+ val generatedTime = nextTime()
+ val currentTime = System.currentTimeMillis()
+
+ generatedTime.millis should be >= 0L
+ generatedTime.millis should be <= currentTime
+ }
+
+ it should "be able to generate a time range value" in {
+
+ val generatedTimeRange = nextTimeRange()
+ val currentTime = System.currentTimeMillis()
+
+ generatedTimeRange.start.millis should be >= 0L
+ generatedTimeRange.start.millis should be <= currentTime
+ generatedTimeRange.end.millis should be >= 0L
+ generatedTimeRange.end.millis should be <= currentTime
+ generatedTimeRange.start.millis should be <= generatedTimeRange.end.millis
+ }
+
+ it should "be able to generate a BigDecimal value" in {
+
+ val defaultGeneratedBigDecimal = nextBigDecimal()
+
+ defaultGeneratedBigDecimal should be >= BigDecimal(0.00)
+ defaultGeneratedBigDecimal should be <= BigDecimal(1000000.00)
+ defaultGeneratedBigDecimal.precision should be(2)
+
+ val unitIntervalBigDecimal = nextBigDecimal(1.00, 8)
+
+ unitIntervalBigDecimal should be >= BigDecimal(0.00)
+ unitIntervalBigDecimal should be <= BigDecimal(1.00)
+ unitIntervalBigDecimal.precision should be(8)
+ }
+
+ it should "be able to generate a specific value from a set of values" in {
+
+ val possibleOptions = Set(1, 3, 5, 123, 0, 9)
+
+ val pick1 = generators.oneOf(possibleOptions)
+ val pick2 = generators.oneOf(possibleOptions)
+ val pick3 = generators.oneOf(possibleOptions)
+
+ possibleOptions should contain(pick1)
+ possibleOptions should contain(pick2)
+ possibleOptions should contain(pick3)
+
+ val pick4 = generators.oneOf(1, 3, 5, 123, 0, 9)
+ val pick5 = generators.oneOf(1, 3, 5, 123, 0, 9)
+ val pick6 = generators.oneOf(1, 3, 5, 123, 0, 9)
+
+ possibleOptions should contain(pick4)
+ possibleOptions should contain(pick5)
+ possibleOptions should contain(pick6)
+
+ Set(pick1, pick2, pick3, pick4, pick5, pick6).size should be >= 1
+ }
+
+ it should "be able to generate array with values generated by generators" in {
+
+ val arrayOfTimes = arrayOf(nextTime(), 16)
+ arrayOfTimes.length should be <= 16
+
+ val arrayOfBigDecimals = arrayOf(nextBigDecimal(), 8)
+ arrayOfBigDecimals.length should be <= 8
+ }
+
+ it should "be able to generate seq with values generated by generators" in {
+
+ val seqOfTimes = seqOf(nextTime(), 16)
+ seqOfTimes.size should be <= 16
+
+ val seqOfBigDecimals = seqOf(nextBigDecimal(), 8)
+ seqOfBigDecimals.size should be <= 8
+ }
+
+ it should "be able to generate vector with values generated by generators" in {
+
+ val vectorOfTimes = vectorOf(nextTime(), 16)
+ vectorOfTimes.size should be <= 16
+
+ val vectorOfStrings = seqOf(nextString(), 8)
+ vectorOfStrings.size should be <= 8
+ }
+
+ it should "be able to generate list with values generated by generators" in {
+
+ val listOfTimes = listOf(nextTime(), 16)
+ listOfTimes.size should be <= 16
+
+ val listOfBigDecimals = seqOf(nextBigDecimal(), 8)
+ listOfBigDecimals.size should be <= 8
+ }
+
+ it should "be able to generate set with values generated by generators" in {
+
+ val setOfTimes = vectorOf(nextTime(), 16)
+ setOfTimes.size should be <= 16
+
+ val setOfBigDecimals = seqOf(nextBigDecimal(), 8)
+ setOfBigDecimals.size should be <= 8
+ }
+
+ it should "be able to generate maps with keys and values generated by generators" in {
+
+ val generatedConstantMap = mapOf(10, "key", 123)
+ generatedConstantMap.size should be <= 1
+ assert(generatedConstantMap.keys.forall(_ == "key"))
+ assert(generatedConstantMap.values.forall(_ == 123))
+
+ val generatedMap = mapOf(10, nextString(10), nextBigDecimal())
+ assert(generatedMap.keys.forall(_.length <= 10))
+ assert(generatedMap.values.forall(_ >= BigDecimal(0.00)))
+ }
+
+ it should "compose deeply" in {
+
+ val generatedNestedMap = mapOf(10, nextString(10), nextPair(nextBigDecimal(), nextOption(123)))
+
+ generatedNestedMap.size should be <= 10
+ generatedNestedMap.keySet.size should be <= 10
+ generatedNestedMap.values.size should be <= 10
+ assert(generatedNestedMap.values.forall(value => !value._2.exists(_ != 123)))
+ }
+}
diff --git a/src/test/scala/com/drivergrp/core/MessagesTest.scala b/src/test/scala/com/drivergrp/core/MessagesTest.scala
new file mode 100644
index 0000000..21fe30a
--- /dev/null
+++ b/src/test/scala/com/drivergrp/core/MessagesTest.scala
@@ -0,0 +1,80 @@
+package com.drivergrp.core
+
+import java.util.Locale
+
+import com.drivergrp.core.logging.Logger
+import com.drivergrp.core.messages.Messages
+import com.typesafe.config.{ConfigException, ConfigFactory}
+import org.mockito.Mockito._
+import org.scalatest.mock.MockitoSugar
+import org.scalatest.{FlatSpec, Matchers}
+
+import scala.collection.JavaConversions._
+
+class MessagesTest extends FlatSpec with Matchers with MockitoSugar {
+
+ val englishLocaleMessages =
+ Map("en.greeting" -> "Hello {0}!", "en.greetingFullName" -> "Hello {0} {1} {2}!", "en.hello" -> "Hello world!")
+
+ "Messages" should "read messages from config and format with parameters" in {
+
+ val log = mock[Logger]
+ val messagesConfig = ConfigFactory.parseMap(englishLocaleMessages)
+
+ val messages = Messages.messages(messagesConfig, log, Locale.US)
+
+ messages("hello") should be("Hello world!")
+ messages("greeting", "Homer") should be("Hello Homer!")
+ messages("greetingFullName", "Homer", "J", "Simpson") should be("Hello Homer J Simpson!")
+ }
+
+ it should "be able to read messages for different locales" in {
+
+ val log = mock[Logger]
+
+ val messagesConfig = ConfigFactory.parseMap(
+ englishLocaleMessages ++ Map(
+ "zh.hello" -> "你好,世界!",
+ "zh.greeting" -> "你好,{0}!",
+ "zh.greetingFullName" -> "你好,{0} {1} {2}!"
+ ))
+
+ val englishMessages = Messages.messages(messagesConfig, log, Locale.US)
+ val englishMessagesToo = Messages.messages(messagesConfig, log, Locale.ENGLISH)
+ val chineseMessages = Messages.messages(messagesConfig, log, Locale.CHINESE)
+
+ englishMessages("hello") should be("Hello world!")
+ englishMessages("greeting", "Homer") should be("Hello Homer!")
+ englishMessages("greetingFullName", "Homer", "J", "Simpson") should be("Hello Homer J Simpson!")
+
+ englishMessagesToo("hello") should be(englishMessages("hello"))
+ englishMessagesToo("greeting", "Homer") should be(englishMessages("greeting", "Homer"))
+ englishMessagesToo("greetingFullName", "Homer", "J", "Simpson") should be(
+ englishMessages("greetingFullName", "Homer", "J", "Simpson"))
+
+ chineseMessages("hello") should be("你好,世界!")
+ chineseMessages("greeting", "Homer") should be("你好,Homer!")
+ chineseMessages("greetingFullName", "Homer", "J", "Simpson") should be("你好,Homer J Simpson!")
+ }
+
+ it should "raise exception when locale is not available" in {
+
+ val log = mock[Logger]
+ val messagesConfig = ConfigFactory.parseMap(englishLocaleMessages)
+
+ an[ConfigException.Missing] should be thrownBy
+ Messages.messages(messagesConfig, log, Locale.GERMAN)
+ }
+
+ it should "log a problem, when there is no message for key" in {
+
+ val log = mock[Logger]
+ val messagesConfig = ConfigFactory.parseMap(englishLocaleMessages)
+
+ val messages = Messages.messages(messagesConfig, log, Locale.US)
+
+ messages("howdy") should be("howdy")
+
+ verify(log).error(s"Message with key 'howdy' not found for locale 'en'")
+ }
+}
diff --git a/src/test/scala/com/drivergrp/core/RestTest.scala b/src/test/scala/com/drivergrp/core/RestTest.scala
new file mode 100644
index 0000000..68be55c
--- /dev/null
+++ b/src/test/scala/com/drivergrp/core/RestTest.scala
@@ -0,0 +1,40 @@
+package com.drivergrp.core
+
+import com.drivergrp.core.time.provider.SystemTimeProvider
+import org.scalatest.{FlatSpec, Matchers}
+
+class RestTest extends FlatSpec with Matchers {
+
+ "Json format for Id" should "read and write correct JSON" in {
+
+ val referenceId = Id[String](1312L)
+
+ val writtenJson = com.drivergrp.core.rest.basicFormats.idFormat.write(referenceId)
+ writtenJson.prettyPrint should be("1312")
+
+ val parsedId = com.drivergrp.core.rest.basicFormats.idFormat.read(writtenJson)
+ parsedId should be(referenceId)
+ }
+
+ "Json format for Name" should "read and write correct JSON" in {
+
+ val referenceName = Name[String]("Homer")
+
+ val writtenJson = com.drivergrp.core.rest.basicFormats.nameFormat.write(referenceName)
+ writtenJson.prettyPrint should be("\"Homer\"")
+
+ val parsedName = com.drivergrp.core.rest.basicFormats.nameFormat.read(writtenJson)
+ parsedName should be(referenceName)
+ }
+
+ "Json format for Time" should "read and write correct JSON" in {
+
+ val referenceTime = new SystemTimeProvider().currentTime()
+
+ val writtenJson = com.drivergrp.core.rest.basicFormats.timeFormat.write(referenceTime)
+ writtenJson.prettyPrint should be("{\n \"timestamp\": " + referenceTime.millis + "\n}")
+
+ val parsedTime = com.drivergrp.core.rest.basicFormats.timeFormat.read(writtenJson)
+ parsedTime should be(referenceTime)
+ }
+}
diff --git a/src/test/scala/com/drivergrp/core/StatsTest.scala b/src/test/scala/com/drivergrp/core/StatsTest.scala
new file mode 100644
index 0000000..c4f449b
--- /dev/null
+++ b/src/test/scala/com/drivergrp/core/StatsTest.scala
@@ -0,0 +1,43 @@
+package com.drivergrp.core
+
+import com.drivergrp.core.logging.Logger
+import com.drivergrp.core.stats.LogStats
+import com.drivergrp.core.time.{Time, TimeRange}
+import org.scalatest.mock.MockitoSugar
+import org.scalatest.{FlatSpec, Matchers}
+import org.mockito.Mockito._
+
+class StatsTest extends FlatSpec with Matchers with MockitoSugar {
+
+ "Stats" should "format and store all recorded data" in {
+
+ val log = mock[Logger]
+ val stats = new LogStats(log)
+
+ stats.recordStats(Seq(), TimeRange(Time(2L), Time(5L)), BigDecimal(123.324))
+ verify(log).audit(s"(2-5)=123.324")
+
+ stats.recordStats("stat", TimeRange(Time(5L), Time(5L)), BigDecimal(333L))
+ verify(log).audit(s"stat(5-5)=333")
+
+ stats.recordStats("stat", Time(934L), 123)
+ verify(log).audit(s"stat(934-934)=123")
+
+ stats.recordStats("stat", Time(0L), 123)
+ verify(log).audit(s"stat(0-0)=123")
+ }
+
+ it should "format BigDecimal with all precision digits" in {
+
+ val log = mock[Logger]
+ val stats = new LogStats(log)
+
+ stats.recordStats(Seq("root", "group", "stat", "substat"),
+ TimeRange(Time(1467381889834L), Time(1468937089834L)),
+ BigDecimal(3.333333333333333))
+ verify(log).audit(s"root.group.stat.substat(1467381889834-1468937089834)=3.333333333333333")
+
+ stats.recordStats("stat", Time(1233L), BigDecimal(0.00000000000000000000001))
+ verify(log).audit(s"stat(1233-1233)=0.000000000000000000000010")
+ }
+}
diff --git a/src/test/scala/com/drivergrp/core/TimeTest.scala b/src/test/scala/com/drivergrp/core/TimeTest.scala
new file mode 100644
index 0000000..ad390c8
--- /dev/null
+++ b/src/test/scala/com/drivergrp/core/TimeTest.scala
@@ -0,0 +1,57 @@
+package com.drivergrp.core
+
+import com.drivergrp.core.time.{Time, _}
+import org.scalatest.{FlatSpec, Matchers}
+
+import scala.concurrent.duration._
+
+class TimeTest extends FlatSpec with Matchers {
+
+ "Time" should "have correct methods to compare" in {
+
+ Time(234L).isAfter(Time(123L)) should be(true)
+ Time(123L).isAfter(Time(123L)) should be(false)
+ Time(123L).isAfter(Time(234L)) should be(false)
+
+ Time(234L).isBefore(Time(123L)) should be(false)
+ Time(123L).isBefore(Time(123L)) should be(false)
+ Time(123L).isBefore(Time(234L)) should be(true)
+ }
+
+ it should "not modify time" in {
+
+ Time(234L).millis should be(234L)
+ }
+
+ it should "support arithmetic with scala.concurrent.duration" in {
+
+ Time(123L).advanceBy(0 minutes).millis should be(123L)
+ Time(123L).advanceBy(1 second).millis should be(123L + Second)
+ Time(123L).advanceBy(4 days).millis should be(123L + 4 * Days)
+ }
+
+ it should "have ordering defined correctly" in {
+
+ Seq(Time(321L), Time(123L), Time(231L)).sorted should
+ contain theSameElementsInOrderAs Seq(Time(123L), Time(231L), Time(321L))
+ }
+
+ it should "reset to the start of the period, e.g. month" in {
+
+ startOfMonth(Time(1468937089834L)) should be(Time(1467381889834L))
+ startOfMonth(Time(1467381889834L)) should be(Time(1467381889834L)) // idempotent
+ }
+
+ it should "have correct textual representations" in {
+
+ textualDate(Time(1468937089834L)) should be("July 19, 2016")
+ textualTime(Time(1468937089834L)) should be("Jul 19, 2016 10:04:49 AM")
+ }
+
+ "TimeRange" should "have duration defined as a difference of start and end times" in {
+
+ TimeRange(Time(321L), Time(432L)).duration should be(111.milliseconds)
+ TimeRange(Time(432L), Time(321L)).duration should be((-111).milliseconds)
+ TimeRange(Time(333L), Time(333L)).duration should be(0.milliseconds)
+ }
+}