Skip to content

Commit 0693353

Browse files
author
Nick Grippin
committed
protocol and tests, needs a fix
1 parent 42efe2f commit 0693353

File tree

5 files changed

+163
-1
lines changed

5 files changed

+163
-1
lines changed

publication/src/main/scala/hmda/publication/reports/national/NationalAggregateReports.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import akka.stream.ActorMaterializer
55
import akka.util.Timeout
66
import com.typesafe.config.ConfigFactory
77
import hmda.query.repository.filing.FilingCassandraRepository
8+
import hmda.publication.reports.protocol.national.N52Protocol._
89

910
import scala.concurrent.Future
1011
import scala.concurrent.duration._
1112
import spray.json._
1213

13-
class NationalAggregateReports (val sys: ActorSystem, val mat: ActorMaterializer) extends FilingCassandraRepository {
14+
class NationalAggregateReports(val sys: ActorSystem, val mat: ActorMaterializer) extends FilingCassandraRepository {
1415
override implicit def system: ActorSystem = sys
1516
override implicit def materializer: ActorMaterializer = mat
1617
val config = ConfigFactory.load()
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package hmda.publication.reports.protocol.national
2+
3+
import hmda.model.publication.reports.ReportTypeEnum._
4+
import hmda.model.publication.reports.{ ApplicantIncome, Disposition }
5+
import hmda.publication.reports.national.N52
6+
import hmda.publication.reports.protocol.{ ApplicantIncomeProtocol, MSAReportProtocol, ReportTypeEnumProtocol }
7+
import spray.json._
8+
9+
object N52Protocol
10+
extends DefaultJsonProtocol
11+
with ReportTypeEnumProtocol
12+
with MSAReportProtocol
13+
with ApplicantIncomeProtocol {
14+
15+
implicit object N52Format extends RootJsonFormat[N52] {
16+
override def write(obj: N52): JsValue = {
17+
JsObject(
18+
"table" -> JsString("5-2"),
19+
"type" -> JsString(NationalAggregate.toString),
20+
"desc" -> JsString(obj.description),
21+
"year" -> JsNumber(obj.year),
22+
"reportDate" -> JsString(obj.reportDate),
23+
"applicantIncomes" -> obj.applicantIncomes.toJson,
24+
"total" -> obj.total.toJson
25+
)
26+
}
27+
28+
override def read(json: JsValue): N52 = json.asJsObject.getFields(
29+
"table",
30+
"type",
31+
"desc",
32+
"year",
33+
"reportDate",
34+
"applicantIncomes",
35+
"total"
36+
) match {
37+
case Seq(table, reportType, description, year, reportDate, applicantIncomes, total) =>
38+
N52(
39+
year.convertTo[Int],
40+
reportDate.convertTo[String],
41+
applicantIncomes.convertTo[List[ApplicantIncome]],
42+
total.convertTo[List[Disposition]]
43+
)
44+
}
45+
}
46+
47+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package hmda.publication.reports.national
2+
3+
import org.scalatest.prop.PropertyChecks
4+
import org.scalatest.{ MustMatchers, PropSpec }
5+
import spray.json._
6+
import NationalAggregateReportGenerators._
7+
import hmda.publication.reports.protocol.national.N52Protocol._
8+
9+
class N52ProtocolSpec extends PropSpec with PropertyChecks with MustMatchers {
10+
11+
property("N52 Report must convert to and from JSON") {
12+
forAll(n52Gen) { n52 =>
13+
n52.toJson.convertTo[N52] mustBe n52
14+
}
15+
}
16+
17+
property("N52 Report must serialize to the correct JSON format") {
18+
forAll(n52Gen) { n52 =>
19+
n52.toJson mustBe JsObject(
20+
"table" -> JsString("5-2"),
21+
"type" -> JsString("National Aggregate"),
22+
"desc" -> JsString("Disposition of Applications for Conventional Home-Purchase Loans, 1-to-4 Family and Manufactured Home Dwellings, by Income, Race, and Ethnicity of Applicant"),
23+
"year" -> JsNumber(n52.year),
24+
"reportDate" -> JsString(n52.reportDate),
25+
"applicantIncomes" -> n52.applicantIncomes.toJson,
26+
"total" -> n52.total.toJson
27+
)
28+
}
29+
}
30+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package hmda.publication.reports.national
2+
3+
import akka.NotUsed
4+
import akka.actor.ActorSystem
5+
import akka.stream.ActorMaterializer
6+
import akka.stream.scaladsl.Source
7+
import hmda.census.model.CbsaLookup
8+
import hmda.model.fi.lar.{ LarGenerators, LoanApplicationRegister }
9+
import hmda.model.publication.reports.ActionTakenTypeEnum._
10+
import hmda.model.publication.reports.ApplicantIncomeEnum.LessThan50PercentOfMSAMedian
11+
import hmda.model.publication.reports.{ EthnicityBorrowerCharacteristic, MinorityStatusBorrowerCharacteristic, RaceBorrowerCharacteristic }
12+
import hmda.query.model.filing.LoanApplicationRegisterQuery
13+
import hmda.query.repository.filing.LarConverter._
14+
import org.scalacheck.Gen
15+
import org.scalatest.{ AsyncWordSpec, BeforeAndAfterAll, MustMatchers }
16+
17+
class N52Spec extends AsyncWordSpec with MustMatchers with LarGenerators with BeforeAndAfterAll {
18+
19+
implicit val system = ActorSystem()
20+
implicit val ec = system.dispatcher
21+
implicit val materializer = ActorMaterializer()
22+
23+
override def afterAll(): Unit = {
24+
super.afterAll()
25+
system.terminate()
26+
}
27+
28+
val fips = CbsaLookup.values.map(_.cbsa)
29+
val fipsGen = Gen.oneOf(fips)
30+
def propType = Gen.oneOf(1, 2).sample.get
31+
32+
val lars = lar100ListGen.sample.get.map { lar: LoanApplicationRegister =>
33+
val geo = lar.geography.copy(msa = fipsGen.sample.get)
34+
val loan = lar.loan.copy(loanType = 1, propertyType = propType, purpose = 1)
35+
lar.copy(geography = geo, loan = loan)
36+
}
37+
38+
val source: Source[LoanApplicationRegisterQuery, NotUsed] = Source
39+
.fromIterator(() => lars.toIterator)
40+
.map(lar => toLoanApplicationRegisterQuery(lar))
41+
42+
val expectedDispositions = List(ApplicationReceived, LoansOriginated, ApprovedButNotAccepted, ApplicationsDenied, ApplicationsWithdrawn, ClosedForIncompleteness)
43+
44+
"Generate an National Aggregate 5-2 report" in {
45+
N52.generate(source).map { result =>
46+
47+
result.table mustBe "5-2"
48+
result.applicantIncomes.size mustBe 5
49+
50+
val lowestIncome = result.applicantIncomes.head
51+
lowestIncome.applicantIncome mustBe LessThan50PercentOfMSAMedian
52+
53+
val races = lowestIncome.borrowerCharacteristics.head.asInstanceOf[RaceBorrowerCharacteristic].races
54+
races.size mustBe 8
55+
56+
val ethnicities = lowestIncome.borrowerCharacteristics(1).asInstanceOf[EthnicityBorrowerCharacteristic].ethnicities
57+
ethnicities.size mustBe 4
58+
59+
val minorityStatuses = lowestIncome.borrowerCharacteristics(2).asInstanceOf[MinorityStatusBorrowerCharacteristic].minoritystatus
60+
minorityStatuses.size mustBe 2
61+
62+
races.head.dispositions.map(_.disposition) mustBe expectedDispositions
63+
}
64+
}
65+
66+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package hmda.publication.reports.national
2+
3+
import java.util.Calendar
4+
5+
import hmda.publication.reports.ReportGenerators._
6+
import hmda.publication.reports.util.DateUtil._
7+
import org.scalacheck.Gen
8+
9+
object NationalAggregateReportGenerators {
10+
implicit def n52Gen: Gen[N52] = {
11+
for {
12+
total <- totalDispositionGen
13+
year = Calendar.getInstance().get(Calendar.YEAR)
14+
reportDate = formatDate(Calendar.getInstance().toInstant)
15+
applicantIncomes <- Gen.listOfN(5, applicantIncomeGen)
16+
} yield N52(year, reportDate, applicantIncomes, total)
17+
}
18+
}

0 commit comments

Comments
 (0)