diff --git a/sport/app/cricket/feed/cricketModel.scala b/sport/app/cricket/feed/cricketModel.scala index 4e882b3c2de..5712a6b096b 100644 --- a/sport/app/cricket/feed/cricketModel.scala +++ b/sport/app/cricket/feed/cricketModel.scala @@ -1,6 +1,8 @@ package cricketModel +import cricket.feed.PlayerNames import play.api.libs.json._ + import java.time.LocalDateTime case class Player(id: String, name: String, firstName: String, lastName: String, initials: String) @@ -8,7 +10,9 @@ case class Player(id: String, name: String, firstName: String, lastName: String, object Player { implicit val writes: OWrites[Player] = Json.writes[Player] } -case class Team(name: String, id: String, home: Boolean, lineup: List[String], players: List[Player]) +case class Team(name: String, id: String, home: Boolean, lineup: List[String], players: List[Player]) { + lazy val uniquePlayerNames = PlayerNames.uniqueNames(players) +} object Team { implicit val writes: OWrites[Team] = Json.writes[Team] diff --git a/sport/app/cricket/feed/cricketPaDeserialisation.scala b/sport/app/cricket/feed/cricketPaDeserialisation.scala index ba7f5999e39..70877c54e8d 100644 --- a/sport/app/cricket/feed/cricketPaDeserialisation.scala +++ b/sport/app/cricket/feed/cricketPaDeserialisation.scala @@ -1,9 +1,10 @@ package conf.cricketPa +import com.madgag.scala.collection.decorators.MapDecorator import common.Chronos import cricket.feed.PlayerNames -import xml.{NodeSeq, XML} +import xml.{Node, NodeSeq, XML} import scala.language.postfixOps import cricketModel._ @@ -71,16 +72,15 @@ object Parser { }.toList - private def parseTeamLineup(lineup: NodeSeq): List[Player] = - lineup.map { player => - Player( - id = (player \ "id").text, - name = (player \ "name").text, - firstName = (player \ "firstName").text, - lastName = (player \ "lastName").text, - initials = (player \ "initials").text, - ) - }.toList + private def parsePlayer(player: Node): Player = Player( + id = (player \ "id").text, + name = (player \ "name").text, + firstName = (player \ "firstName").text, + lastName = (player \ "lastName").text, + initials = (player \ "initials").text, + ) + + private def parseTeamLineup(lineup: NodeSeq): List[Player] = lineup.map(parsePlayer).toList private def getStatistic(statistics: NodeSeq, statistic: String): String = (statistics \ "statistic").find(node => (node \ "@type").text == statistic).map(_.text).getOrElse("") @@ -91,7 +91,8 @@ object Parser { val inningsOrder = (singleInnings \ "@order").text.toInt val battingTeam = (singleInnings \ "batting" \ "team" \ "name").text - val bowlingTeam = teams.find(_.name == (singleInnings \ "bowling" \ "team" \ "name)").text) + val bowlingTeamName = (singleInnings \ "bowling" \ "team" \ "name").text + val bowlingTeam = teams.find(_.name == bowlingTeamName) Innings( inningsOrder, @@ -115,32 +116,48 @@ object Parser { .toList .sortBy(_.order) - def descriptionWithUniqueNames( - bowlingTeam: Option[Team], - catcherId: String, - bowlerId: String, - description: String, - ): String = { - val players = bowlingTeam.map(team => PlayerNames.uniqueNames(team.players)).get - - description - .replaceFirst("c\\s+\\w+\\s?", s"c ${players.getOrElse(catcherId, "")} ") - .replaceFirst("st\\s+\\w+\\s?", s"st ${players.getOrElse(catcherId, "")} ") - .replaceFirst("b\\s+\\w+\\s?", s"b ${players.getOrElse(bowlerId, "")}") + case class Dismissal(items: Seq[(String, String)]) { + + def description(dismissal: NodeSeq, f: Player => String): String = { + for { + (nodeName, prefix) <- items + } yield { + s"$prefix ${f(parsePlayer((dismissal \ nodeName \ "player").head))}" + } + }.mkString(" ") + + } + + val dismissalTypes: Map[String, Dismissal] = Map( + "caught" -> Seq("caughtBy" -> "st", "bowledBy" -> "b"), // c Rathnayake b de Silva + "caught-sub" -> Seq("bowledBy" -> "c Sub b"), // c Sub b Kumara + "caught-and-bowled" -> Seq("caughtBy" -> "c & b"), // c & b Woakes + "stumped" -> Seq("caughtBy" -> "st", "bowledBy" -> "b"), // st Ambrose b Patel + "run-out" -> Seq("caughtBy" -> "Run Out"), // Run Out Stone + "lbw" -> Seq("bowledBy" -> "lbw b"), // lbw b Stone + "bowled" -> Seq("bowledBy" -> "b"), // b Kumara + ).mapV(Dismissal) + + def parseDismissal(dismissal: NodeSeq, bowlingTeamOpt: Option[Team]): String = { + val description = (dismissal \ "description").text + ( + for { + bowlingTeam <- bowlingTeamOpt + dismissalDescriber <- dismissalTypes.get(dismissal \@ "type") + if description == dismissalDescriber.description(dismissal, _.lastName) + } yield { + dismissalDescriber.description( + dismissal, + player => bowlingTeam.uniquePlayerNames.getOrElse(player.id, player.name), + ) + } + ).getOrElse(description) } private def parseInningsBatters(batters: NodeSeq, bowlingTeam: Option[Team]): List[InningsBatter] = { batters .map { batter => - val dismissalDescription = (batter \ "dismissal" \ "description").text - val catcherId = - if (dismissalDescription.contains("c") || dismissalDescription.contains("st")) - (batter \ "dismissal" \ "caughtBy" \ "player" \ "@id").text - else "" - val bowlerId = - if (dismissalDescription.contains("b")) (batter \ "dismissal" \ "bowledBy" \ "player" \ "@id").text else "" - InningsBatter( (batter \ "player" \ "name").text, (batter \ "@order").text.toInt, @@ -149,7 +166,7 @@ object Parser { getStatistic(batter, "fours") toInt, getStatistic(batter, "sixes") toInt, (batter \ "status").text == "batted", - descriptionWithUniqueNames(bowlingTeam, dismissalDescription, catcherId, bowlerId), + parseDismissal(batter \ "dismissal", bowlingTeam), getStatistic(batter, "on-strike").toInt > 0, getStatistic(batter, "runs-scored").toInt > 0, ) diff --git a/sport/test/cricket/feed/CricketPaDeserialisationTest.scala b/sport/test/cricket/feed/CricketPaDeserialisationTest.scala index c8a391d693c..bf956404d37 100644 --- a/sport/test/cricket/feed/CricketPaDeserialisationTest.scala +++ b/sport/test/cricket/feed/CricketPaDeserialisationTest.scala @@ -1,184 +1,32 @@ package cricket.feed -import conf.cricketPa.Parser.descriptionWithUniqueNames -import cricketModel.{Player, Team} +import org.apache.pekko.actor.{ActorSystem => PekkoActorSystem} +import conf.cricketPa.PaFeed +import org.scalatest.{BeforeAndAfterAll, DoNotDiscover} +import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures} import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers - -class CricketPaDeserialisationTest extends AnyFlatSpec with Matchers { - - val teamWithPlayersWithUniqueSurnames = Team( - name = "Sri Lanka", - id = "0cbc23be-e7cc-9574-611a-06561460eb8b", - home = false, - lineup = List("Asitha Fernando", "Dimuth Karunaratne", "Kusal Mendis"), - players = List( - Player( - id = "ae5e0dbf-d6af-70ec-76ef-1f8e83230405", - name = "Asitha Fernando", - firstName = "Asitha", - lastName = "Fernando", - initials = "A M", - ), - Player( - id = "c32cd9c7-d38a-93e7-e874-f5f4a5197812", - name = "Dimuth Karunaratne", - firstName = "Frank", - lastName = "Karunaratne", - initials = "F D M", - ), - Player( - id = "b96e5130-0348-9659-e3c6-ba887f306eeb", - name = "Kusal Mendis", - firstName = "Balapuwaduge", - lastName = "Mendis", - initials = "B K G", - ), - Player( - id = "46a55cb7-49f5-e9f7-7560-c7110b0f68ec", - name = "Dinesh Chandimal", - firstName = "Lokuge", - lastName = "Chandimal", - initials = "L D", - ), - ), - ) - - val teamWithPlayersWithTheSameSurname = Team( - name = "Sri Lanka", - id = "0cbc23be-e7cc-9574-611a-06561460eb8b", - home = false, - lineup = List("Asitha Fernando", "Dimuth Karunaratne", "Nishan Madushka"), - players = List( - Player( - id = "ae5e0dbf-d6af-70ec-76ef-1f8e83230405", - name = "Asitha Fernando", - firstName = "Asitha", - lastName = "Fernando", - initials = "A M", - ), - Player( - id = "c32cd9c7-d38a-93e7-e874-f5f4a5197812", - name = "Dimuth Karunaratne", - firstName = "Frank", - lastName = "Karunaratne", - initials = "F D M", - ), - Player( - id = "d29c8d1c-29b4-517e-5b62-1277065801b2", - name = "Nishan Madushka", - firstName = "Kottasinghakkarage", - lastName = "Fernando", - initials = "K N M", - ), - Player( - id = "46a55cb7-49f5-e9f7-7560-c7110b0f68ec", - name = "Dinesh Chandimal", - firstName = "Lokuge", - lastName = "Chandimal", - initials = "L D", - ), - ), - ) - - "descriptionWithUniqueNames" should "include catcher's and bowler's surname if this is enough to determine their unique name when dismissal type is caught" in { - - descriptionWithUniqueNames( - bowlingTeam = Some(teamWithPlayersWithUniqueSurnames), - catcherId = "46a55cb7-49f5-e9f7-7560-c7110b0f68ec", - bowlerId = "ae5e0dbf-d6af-70ec-76ef-1f8e83230405", - description = "c Chandimal b Fernando", - ) shouldEqual "c Chandimal b Fernando" - - } - - it should "include catcher's first name and surname if other player with the same surname exists in the same team when dismissal type is caught" in { - descriptionWithUniqueNames( - bowlingTeam = Some(teamWithPlayersWithTheSameSurname), - catcherId = "ae5e0dbf-d6af-70ec-76ef-1f8e83230405", - bowlerId = "46a55cb7-49f5-e9f7-7560-c7110b0f68ec", - description = "c Chandimal b Fernando", - ) shouldEqual "c Asitha Fernando b Chandimal" - } - - it should "include bowler's first name and surname if other player with the same surname exists in the same team when dismissal type is caught" in { - descriptionWithUniqueNames( - bowlingTeam = Some(teamWithPlayersWithTheSameSurname), - catcherId = "46a55cb7-49f5-e9f7-7560-c7110b0f68ec", - bowlerId = "ae5e0dbf-d6af-70ec-76ef-1f8e83230405", - description = "c Chandimal b Fernando", - ) shouldEqual "c Chandimal b Asitha Fernando" - } - - it should "include bowler's surname if this is enough to determine their unique name when dismissal type is bowled" in { - descriptionWithUniqueNames( - bowlingTeam = Some(teamWithPlayersWithUniqueSurnames), - catcherId = "", - bowlerId = "ae5e0dbf-d6af-70ec-76ef-1f8e83230405", - description = "b Fernando", - ) shouldEqual "b Fernando" - } - - it should "include bowler's first name and surname if other player with the same surname exists in the same team when dismissal type is bowled" in { - descriptionWithUniqueNames( - bowlingTeam = Some(teamWithPlayersWithTheSameSurname), - catcherId = "", - bowlerId = "ae5e0dbf-d6af-70ec-76ef-1f8e83230405", - description = "b Fernando", - ) shouldEqual "b Asitha Fernando" - } - - it should "include catcher's surname if this is enough to determine their unique name when dismissal type is stumped" in { - descriptionWithUniqueNames( - bowlingTeam = Some(teamWithPlayersWithUniqueSurnames), - catcherId = "46a55cb7-49f5-e9f7-7560-c7110b0f68ec", - bowlerId = "ae5e0dbf-d6af-70ec-76ef-1f8e83230405", - description = "st Chandimal b Fernando", - ) shouldEqual "st Chandimal b Fernando" - } - - it should "include catcher's first name and surname if other player with the same surname exists in the same team when dismissal type is stumped" in { - descriptionWithUniqueNames( - bowlingTeam = Some(teamWithPlayersWithTheSameSurname), - catcherId = "46a55cb7-49f5-e9f7-7560-c7110b0f68ec", - bowlerId = "ae5e0dbf-d6af-70ec-76ef-1f8e83230405", - description = "st Chandimal b Fernando", - ) shouldEqual "st Chandimal b Asitha Fernando" - } - - it should "include bowler's surname if this is enough to determine their unique name when dismissal type is lbw" in { - descriptionWithUniqueNames( - bowlingTeam = Some(teamWithPlayersWithUniqueSurnames), - catcherId = "", - bowlerId = "ae5e0dbf-d6af-70ec-76ef-1f8e83230405", - description = "lbw b Fernando", - ) shouldEqual "lbw b Fernando" - } - - it should "include bowler's first name and surname if other player with the same surname exists in the same team when dismissal type is lbw" in { - descriptionWithUniqueNames( - bowlingTeam = Some(teamWithPlayersWithTheSameSurname), - catcherId = "", - bowlerId = "ae5e0dbf-d6af-70ec-76ef-1f8e83230405", - description = "lbw b Fernando", - ) shouldEqual "lbw b Asitha Fernando" - } - - it should "be the same as initial description when dismissal type is not-out" in { - descriptionWithUniqueNames( - bowlingTeam = Some(teamWithPlayersWithTheSameSurname), - catcherId = "", - bowlerId = "", - description = "Not Out", - ) shouldEqual "Not Out" - } - - it should "be the same as initial description when dismissal type is yet-to-bat" in { - descriptionWithUniqueNames( - bowlingTeam = Some(teamWithPlayersWithTheSameSurname), - catcherId = "", - bowlerId = "", - description = "Yet to Bat", - ) shouldEqual "Yet to Bat" +import test.{ConfiguredTestSuite, WithMaterializer, WithTestApplicationContext, WithTestExecutionContext, WithTestWsClient} + +@DoNotDiscover class CricketPaDeserialisationTest + extends AnyFlatSpec + with Matchers + with ConfiguredTestSuite + with BeforeAndAfterAll + with WithMaterializer + with WithTestWsClient + with WithTestApplicationContext + with WithTestExecutionContext + with ScalaFutures + with IntegrationPatience + { + val actorSystem = PekkoActorSystem() + val paFeed = new PaFeed(wsClient, actorSystem, materializer) + + whenReady(paFeed.getMatch("39145392-3f2e-8022-35f3-eac0b0654610")){ + cricketMatch => { + cricketMatch.innings.head.batters.head.howOut shouldBe "" + + } + } } -}