Skip to content

Commit

Permalink
Merge pull request #1 from bbc/scala-updates
Browse files Browse the repository at this point in the history
Updates and tweaks
  • Loading branch information
rosebbc authored Jul 17, 2024
2 parents 6272c9e + 4bf2589 commit 168469f
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 53 deletions.
6 changes: 5 additions & 1 deletion election-api-scala/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The API has 3 endpoints:

During your assessment we will ask you to work though the task in `tasks.md` with a pair. Please do not work on or complete these prior to the assessment.

:warning: If you make any changes to the code, please ensure you return it to it's initial (HEAD) state before your assessment.
__Warning:__ If you make any changes to the code, please ensure you return it to it's initial (HEAD) state before your assessment.

## Prerequisites
- Java 11
Expand All @@ -36,6 +36,10 @@ During your assessment we will ask you to work though the task in `tasks.md` wit

`sbt run`

You may get a port error when you try to run this. If so, run the following command:

`export PLAY_HTTP_PORT=9001`

### To Test

`sbt test`
3 changes: 1 addition & 2 deletions election-api-scala/app/controllers/ResultsController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class ResultsController @Inject()(val controllerComponents: ControllerComponents
}

def getScoreboard: Action[AnyContent] = Action {

Ok(Json.toJson(Scoreboard(0)))
Ok(Json.toJson(None))
}
}
6 changes: 4 additions & 2 deletions election-api-scala/app/model/PartyResult.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ case class ConstituencyResult(id: Int, name: String, seqNo: Int, partyResults: S

case class ApiResponse (error: String, message: String)


case class Scoreboard(declared:Int)
// TODO: this class should hold:
// - the overall winner (if there is one)
// - the seats that each party wins in Parliament
case class Scoreboard(winner: String)
5 changes: 2 additions & 3 deletions election-api-scala/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ version := "1.0-SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayScala)

scalaVersion := "2.13.6"
scalaVersion := "2.13.14"

libraryDependencies += guice
libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "5.0.0" % Test

libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "7.0.1" % Test
2 changes: 1 addition & 1 deletion election-api-scala/project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.5.2
sbt.version=1.10.1
4 changes: 2 additions & 2 deletions election-api-scala/project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.8")
addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0")
addSbtPlugin("org.playframework" % "sbt-plugin" % "3.0.4")
addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.16.2")
16 changes: 5 additions & 11 deletions election-api-scala/tasks.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
### Task

The product owner has asked that we implement the scoreboard endpoint.

First version: First Past the Post
#### First Past the Post

For each constituency a winner can be declared:
1. if we have votes for that constituency
2. The winning party is which ever party received a plurality of votes, e.g. whoever receives the most votes
For each constituency a winner can be declared if we have votes for at least one party in that constituency.
The winning party is which ever party received a plurality of votes, e.g. whoever receives the most votes.

Someone wins in the UK if they receive half of the constituency seats in Parliament (325).
So if a party has received 325 or more seats it can be declared the winner overall.
Expand All @@ -16,16 +16,10 @@ The scoreboard should show:
- The seats for each party
- The overall winner (i.e. the party with 325 or more seats) if there is one

There is a case class [Scoreboard](app/model/PartyResult.scala) ready to be extended and an
There is a case class [Scoreboard](app/model/PartyResult.scala) which you should alter to show the above results and an
endpoint controller to put your implementation: [ResultsController](app/controllers/ResultsController.scala). You will also need to complete
the [tests](test/controllers/ResultsControllerSpec.scala) as part of your implementation.

Bonus information for the scoreboard:
- The total votes for each party
- The total share of the vote for each party. So the percentage of votes for each party.


### Possible other implementations

- Absolute majority required. Someone needs 50% + 1 votes or a run off is triggered (check the data that's probably all constituencies)
- Allocate the seats from the total declarations based on % of vote share
50 changes: 19 additions & 31 deletions election-api-scala/test/controllers/ResultsControllerSpec.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package controllers

import akka.stream.Materializer
import model.Scoreboard
import org.scalatestplus.play._
import org.scalatestplus.play.guice._
Expand All @@ -10,7 +9,6 @@ import play.api.libs.json.{Json, OFormat}
import service.MapResultService

class ResultsControllerSpec extends PlaySpec with GuiceOneAppPerTest with Injecting {
implicit lazy val materializer: Materializer = app.materializer
//TODO: You will need the json format for any classes used within the Scoreboard here
implicit val scoreboardJson: OFormat[Scoreboard] = Json.format[Scoreboard]

Expand All @@ -21,47 +19,37 @@ class ResultsControllerSpec extends PlaySpec with GuiceOneAppPerTest with Inject

"Test first 5 results" in {
val scoreboard = runXResults(5)
scoreboard match {
case Some(sc) => matchScoreboard(scoreboard = sc, LabSeats = 4, LDSeats = 1)
case None => fail("Didn't return a scoreboard")
}
scoreboard must not be empty
// LAB = 4
// LD = 1
// winner = noone
}

"First 100 results" in {
val scoreboard = runXResults(100)
scoreboard match {
case Some(sc) => matchScoreboard(scoreboard = sc, LabSeats = 56, LDSeats = 12, ConSeats = 31)
case None => fail("Didn't return a scoreboard")
}
scoreboard must not be empty
// LD == 12
// LAB == 56
// CON == 31
// winner = noone
}

"First 554 results" in {
val scoreboard = runXResults(554)
scoreboard match {
case Some(sc) => matchScoreboard(scoreboard = sc, LabSeats = 325, LDSeats = 52, ConSeats = 167, winner = Some("LAB"))
case None => fail("Didn't return a scoreboard")
}
scoreboard must not be empty
// LD == 52
// LAB = 325
// CON = 167
// winner = LAB
}

"All results" in {
val scoreboard = runXResults(650)
scoreboard match {
case Some(sc) => matchScoreboard(scoreboard = sc, LabSeats = 349, LDSeats = 62, ConSeats = 210, winner = Some("LAB"))
case None => fail("Didn't return a scoreboard")
}
}

def matchScoreboard(scoreboard: Scoreboard, LabSeats: Int = 0,
LDSeats: Int = 0, ConSeats: Int = 0, winner: Option[String] = None) {
var ld, lab, con = 0

//TODO: set the seats by party

ld mustEqual LDSeats
lab mustEqual LabSeats
con mustEqual ConSeats
// something mustEqual winner
fail("Implement me")
scoreboard must not be empty
// LD == 62
// LAB == 349
// CON == 210
// winner = LAB
}

def runXResults(number: Int): Option[Scoreboard] = {
Expand Down

0 comments on commit 168469f

Please sign in to comment.