mirror of
				https://github.com/arcan1s/ffxivbis.git
				synced 2025-10-30 13:13:41 +00:00 
			
		
		
		
	more tests
This commit is contained in:
		| @ -11,8 +11,7 @@ package me.arcanis.ffxivbis.http | |||||||
| import akka.actor.ActorRef | import akka.actor.ActorRef | ||||||
| import akka.pattern.ask | import akka.pattern.ask | ||||||
| import akka.util.Timeout | import akka.util.Timeout | ||||||
| import me.arcanis.ffxivbis.models.{Player, PlayerId} | import me.arcanis.ffxivbis.models.{Party, Player, PlayerId} | ||||||
| import me.arcanis.ffxivbis.service.Party |  | ||||||
| import me.arcanis.ffxivbis.service.impl.{DatabaseBiSHandler, DatabasePartyHandler} | import me.arcanis.ffxivbis.service.impl.{DatabaseBiSHandler, DatabasePartyHandler} | ||||||
|  |  | ||||||
| import scala.concurrent.{ExecutionContext, Future} | import scala.concurrent.{ExecutionContext, Future} | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ case class PieceResponse( | |||||||
|   @Schema(description = "is piece tome gear", required = true) isTome: Boolean, |   @Schema(description = "is piece tome gear", required = true) isTome: Boolean, | ||||||
|   @Schema(description = "job name to which piece belong or AnyJob", required = true, example = "DNC") job: String, |   @Schema(description = "job name to which piece belong or AnyJob", required = true, example = "DNC") job: String, | ||||||
|   @Schema(description = "piece name", required = true, example = "body") piece: String) { |   @Schema(description = "piece name", required = true, example = "body") piece: String) { | ||||||
|   def toPiece: Piece = Piece(piece, isTome, Job.fromString(job)) |   def toPiece: Piece = Piece(piece, isTome, Job.withName(job)) | ||||||
| } | } | ||||||
|  |  | ||||||
| object PieceResponse { | object PieceResponse { | ||||||
|  | |||||||
| @ -16,5 +16,5 @@ case class PlayerIdResponse( | |||||||
|   @Schema(description = "job name", required = true, example = "DNC") job: String, |   @Schema(description = "job name", required = true, example = "DNC") job: String, | ||||||
|   @Schema(description = "player nick name", required = true, example = "Siuan Sanche") nick: String) { |   @Schema(description = "player nick name", required = true, example = "Siuan Sanche") nick: String) { | ||||||
|   def withPartyId(partyId: String): PlayerId = |   def withPartyId(partyId: String): PlayerId = | ||||||
|     PlayerId(partyId, Job.fromString(job), nick) |     PlayerId(partyId, Job.withName(job), nick) | ||||||
| } | } | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ case class PlayerResponse( | |||||||
|   @Schema(description = "link to best in slot", example = "https://ffxiv.ariyala.com/19V5R") link: Option[String], |   @Schema(description = "link to best in slot", example = "https://ffxiv.ariyala.com/19V5R") link: Option[String], | ||||||
|   @Schema(description = "player loot priority") priority: Option[Int]) { |   @Schema(description = "player loot priority") priority: Option[Int]) { | ||||||
|   def toPlayer: Player = |   def toPlayer: Player = | ||||||
|     Player(partyId, Job.fromString(job), nick, |     Player(partyId, Job.withName(job), nick, | ||||||
|       BiS(bis.getOrElse(Seq.empty).map(_.toPiece)), loot.getOrElse(Seq.empty).map(_.toPiece), |       BiS(bis.getOrElse(Seq.empty).map(_.toPiece)), loot.getOrElse(Seq.empty).map(_.toPiece), | ||||||
|       link, priority.getOrElse(0)) |       link, priority.getOrElse(0)) | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,8 +14,7 @@ import akka.http.scaladsl.server.Directives._ | |||||||
| import akka.http.scaladsl.server._ | import akka.http.scaladsl.server._ | ||||||
| import akka.util.Timeout | import akka.util.Timeout | ||||||
| import me.arcanis.ffxivbis.http.UserHelper | import me.arcanis.ffxivbis.http.UserHelper | ||||||
| import me.arcanis.ffxivbis.models.{Permission, User} | import me.arcanis.ffxivbis.models.{Party, Permission, User} | ||||||
| import me.arcanis.ffxivbis.service.Party |  | ||||||
|  |  | ||||||
| class IndexView(storage: ActorRef)(implicit timeout: Timeout) | class IndexView(storage: ActorRef)(implicit timeout: Timeout) | ||||||
|   extends UserHelper(storage) { |   extends UserHelper(storage) { | ||||||
|  | |||||||
| @ -92,7 +92,7 @@ object PlayerView { | |||||||
|           form(action:=s"/party/$partyId/players", method:="post")( |           form(action:=s"/party/$partyId/players", method:="post")( | ||||||
|             input(name:="nick", id:="nick", placeholder:="nick", title:="nick", `type`:="nick"), |             input(name:="nick", id:="nick", placeholder:="nick", title:="nick", `type`:="nick"), | ||||||
|             select(name:="job", id:="job", title:="job") |             select(name:="job", id:="job", title:="job") | ||||||
|                   (for (job <- Job.groupAll) yield option(job.toString)), |                   (for (job <- Job.jobs) yield option(job.toString)), | ||||||
|             input(name:="link", id:="link", placeholder:="player bis link", title:="link", `type`:="text"), |             input(name:="link", id:="link", placeholder:="player bis link", title:="link", `type`:="text"), | ||||||
|             input(name:="prioiry", id:="priority", placeholder:="priority", title:="priority", `type`:="number", value:="0"), |             input(name:="prioiry", id:="priority", placeholder:="priority", title:="priority", `type`:="number", value:="0"), | ||||||
|             input(name:="action", id:="action", `type`:="hidden", value:="add"), |             input(name:="action", id:="action", `type`:="hidden", value:="add"), | ||||||
|  | |||||||
| @ -76,5 +76,5 @@ object BiS { | |||||||
|   def apply(): BiS = BiS(Seq.empty) |   def apply(): BiS = BiS(Seq.empty) | ||||||
|  |  | ||||||
|   def apply(pieces: Seq[Piece]): BiS = |   def apply(pieces: Seq[Piece]): BiS = | ||||||
|     BiS(pieces.map { piece => piece.piece -> Some(piece) }.toMap) |     BiS(pieces.map(piece => piece.piece -> Some(piece)).toMap) | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,65 +9,95 @@ | |||||||
| package me.arcanis.ffxivbis.models | package me.arcanis.ffxivbis.models | ||||||
|  |  | ||||||
| object Job { | object Job { | ||||||
|   sealed trait Job |   sealed trait RightSide | ||||||
|  |   object AccessoriesDex extends RightSide | ||||||
|  |   object AccessoriesInt extends RightSide | ||||||
|  |   object AccessoriesMnd extends RightSide | ||||||
|  |   object AccessoriesStr extends RightSide | ||||||
|  |   object AccessoriesVit extends RightSide | ||||||
|  |  | ||||||
|  |   sealed trait LeftSide | ||||||
|  |   object BodyCasters extends LeftSide | ||||||
|  |   object BodyDrgs extends LeftSide | ||||||
|  |   object BodyHealers extends LeftSide | ||||||
|  |   object BodyMnks extends LeftSide | ||||||
|  |   object BodyNins extends LeftSide | ||||||
|  |   object BodyTanks extends LeftSide | ||||||
|  |   object BodyRanges extends LeftSide | ||||||
|  |  | ||||||
|  |   sealed trait Job { | ||||||
|  |     def leftSide: LeftSide | ||||||
|  |     def rightSide: RightSide | ||||||
|  |  | ||||||
|  |     // conversion to string to avoid recursion | ||||||
|  |     override def equals(obj: Any): Boolean = { | ||||||
|  |       def canEqual(obj: Any): Boolean = obj.isInstanceOf[Job] | ||||||
|  |       def equality(objRepr: String): Boolean = objRepr match { | ||||||
|  |         case _ if objRepr == AnyJob.toString => true | ||||||
|  |         case _ if this.toString == AnyJob.toString => true | ||||||
|  |         case _ => this.toString == obj.toString | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       canEqual(obj) && equality(obj.toString) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   case object AnyJob extends Job { |   case object AnyJob extends Job { | ||||||
|     override def equals(obj: Any): Boolean = obj match { |     val leftSide: LeftSide = null | ||||||
|       case Job => true |     val rightSide: RightSide = null | ||||||
|       case _ => false |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   case object PLD extends Job |   trait Casters extends Job { | ||||||
|   case object WAR extends Job |     val leftSide: LeftSide = BodyCasters | ||||||
|   case object DRK extends Job |     val rightSide: RightSide = AccessoriesInt | ||||||
|   case object GNB extends Job |  | ||||||
|  |  | ||||||
|   case object WHM extends Job |  | ||||||
|   case object SCH extends Job |  | ||||||
|   case object AST extends Job |  | ||||||
|  |  | ||||||
|   case object MNK extends Job |  | ||||||
|   case object DRG extends Job |  | ||||||
|   case object NIN extends Job |  | ||||||
|   case object SAM extends Job |  | ||||||
|  |  | ||||||
|   case object BRD extends Job |  | ||||||
|   case object MCH extends Job |  | ||||||
|   case object DNC extends Job |  | ||||||
|  |  | ||||||
|   case object BLM extends Job |  | ||||||
|   case object SMN extends Job |  | ||||||
|   case object RDM extends Job |  | ||||||
|  |  | ||||||
|   def groupAccessoriesDex: Seq[Job.Job] = groupRanges :+ NIN |  | ||||||
|   def groupAccessoriesStr: Seq[Job.Job] = groupMnk :+ DRG |  | ||||||
|   def groupAll: Seq[Job.Job] = groupCasters ++ groupHealers ++ groupRanges ++ groupTanks |  | ||||||
|   def groupCasters: Seq[Job.Job] = Seq(BLM, SMN, RDM) |  | ||||||
|   def groupHealers: Seq[Job.Job] = Seq(WHM, SCH, AST) |  | ||||||
|   def groupMnk: Seq[Job.Job] = Seq(MNK, SAM) |  | ||||||
|   def groupRanges: Seq[Job.Job] = Seq(BRD, MCH, DNC) |  | ||||||
|   def groupTanks: Seq[Job.Job] = Seq(PLD, WAR, DRK, GNB) |  | ||||||
|  |  | ||||||
|   def groupFull: Seq[Seq[Job.Job]] = Seq(groupCasters, groupHealers, groupMnk, groupRanges, groupTanks) |  | ||||||
|   def groupRight: Seq[Seq[Job.Job]] = Seq(groupAccessoriesDex, groupAccessoriesStr) |  | ||||||
|  |  | ||||||
|   def fromString(job: String): Job.Job = groupAll.find(_.toString == job.toUpperCase).orNull |  | ||||||
|  |  | ||||||
|   def hasSameLoot(left: Job, right: Job, piece: Piece): Boolean = { |  | ||||||
|     def isAccessory(piece: Piece): Boolean = piece match { |  | ||||||
|       case _: PieceAccessory => true |  | ||||||
|       case _ => false |  | ||||||
|     } |  | ||||||
|     def isWeapon(piece: Piece): Boolean = piece match { |  | ||||||
|       case _: PieceWeapon => true |  | ||||||
|       case _ => false |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (left == right) true |  | ||||||
|     else if (isWeapon(piece)) false |  | ||||||
|     else if (groupFull.exists(group => group.contains(left) && group.contains(right))) true |  | ||||||
|     else if (isAccessory(piece) && groupRight.exists(group => group.contains(left) && group.contains(right))) true |  | ||||||
|     else false |  | ||||||
|   } |   } | ||||||
|  |   trait Healers extends Job { | ||||||
|  |     val leftSide: LeftSide = BodyHealers | ||||||
|  |     val rightSide: RightSide = AccessoriesMnd | ||||||
|  |   } | ||||||
|  |   trait Mnks extends Job { | ||||||
|  |     val leftSide: LeftSide = BodyMnks | ||||||
|  |     val rightSide: RightSide = AccessoriesStr | ||||||
|  |   } | ||||||
|  |   trait Tanks extends Job { | ||||||
|  |     val leftSide: LeftSide = BodyTanks | ||||||
|  |     val rightSide: RightSide = AccessoriesVit | ||||||
|  |   } | ||||||
|  |   trait Ranges extends Job { | ||||||
|  |     val leftSide: LeftSide = BodyRanges | ||||||
|  |     val rightSide: RightSide = AccessoriesDex | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   case object PLD extends Tanks | ||||||
|  |   case object WAR extends Tanks | ||||||
|  |   case object DRK extends Tanks | ||||||
|  |   case object GNB extends Tanks | ||||||
|  |  | ||||||
|  |   case object WHM extends Healers | ||||||
|  |   case object SCH extends Healers | ||||||
|  |   case object AST extends Healers | ||||||
|  |  | ||||||
|  |   case object MNK extends Mnks | ||||||
|  |   case object DRG extends Job { | ||||||
|  |     val leftSide: LeftSide = BodyDrgs | ||||||
|  |     val rightSide: RightSide = AccessoriesStr | ||||||
|  |   } | ||||||
|  |   case object NIN extends Job { | ||||||
|  |     val leftSide: LeftSide = BodyNins | ||||||
|  |     val rightSide: RightSide = AccessoriesDex | ||||||
|  |   } | ||||||
|  |   case object SAM extends Mnks | ||||||
|  |  | ||||||
|  |   case object BRD extends Ranges | ||||||
|  |   case object MCH extends Ranges | ||||||
|  |   case object DNC extends Ranges | ||||||
|  |  | ||||||
|  |   case object BLM extends Casters | ||||||
|  |   case object SMN extends Casters | ||||||
|  |   case object RDM extends Casters | ||||||
|  |  | ||||||
|  |   lazy val jobs: Seq[Job] = | ||||||
|  |     Seq(PLD, WAR, DRK, GNB, WHM, SCH, AST, MNK, DRG, NIN, SAM, BRD, MCH, DNC, BLM, SMN, RDM) | ||||||
|  |  | ||||||
|  |   def withName(job: String): Job.Job = jobs.find(_.toString == job.toUpperCase).getOrElse(AnyJob) | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,20 +6,18 @@ | |||||||
|  * |  * | ||||||
|  * License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause |  * License: 3-clause BSD, see https://opensource.org/licenses/BSD-3-Clause | ||||||
|  */ |  */ | ||||||
| package me.arcanis.ffxivbis.service | package me.arcanis.ffxivbis.models | ||||||
| 
 | 
 | ||||||
| import com.typesafe.config.Config | import com.typesafe.config.Config | ||||||
| import com.typesafe.scalalogging.StrictLogging | import com.typesafe.scalalogging.StrictLogging | ||||||
| import me.arcanis.ffxivbis.models.{BiS, Loot, Piece, Player, PlayerId} | import me.arcanis.ffxivbis.service.LootSelector | ||||||
| 
 | 
 | ||||||
| import scala.jdk.CollectionConverters._ | import scala.jdk.CollectionConverters._ | ||||||
| import scala.util.Random | import scala.util.Random | ||||||
| 
 | 
 | ||||||
| case class Party(partyId: String, config: Config, players: Map[PlayerId, Player]) | case class Party(partyId: String, rules: Seq[String], players: Map[PlayerId, Player]) | ||||||
|   extends StrictLogging { |   extends StrictLogging { | ||||||
| 
 |   require(players.keys.forall(_.partyId == partyId), "party id must be same") | ||||||
|   private val rules = |  | ||||||
|     config.getStringList("me.arcanis.ffxivbis.settings.priority").asScala.toSeq |  | ||||||
| 
 | 
 | ||||||
|   def getPlayers: Seq[Player] = players.values.toSeq |   def getPlayers: Seq[Player] = players.values.toSeq | ||||||
|   def player(playerId: PlayerId): Option[Player] = players.get(playerId) |   def player(playerId: PlayerId): Option[Player] = players.get(playerId) | ||||||
| @ -38,8 +36,11 @@ case class Party(partyId: String, config: Config, players: Map[PlayerId, Player] | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| object Party { | object Party { | ||||||
|  |   private def getRules(config: Config): Seq[String] = | ||||||
|  |     config.getStringList("me.arcanis.ffxivbis.settings.priority").asScala.toSeq | ||||||
|  | 
 | ||||||
|   def apply(partyId: Option[String], config: Config): Party = |   def apply(partyId: Option[String], config: Config): Party = | ||||||
|     new Party(partyId.getOrElse(randomPartyId), config, Map.empty) |     new Party(partyId.getOrElse(randomPartyId), getRules(config), Map.empty) | ||||||
| 
 | 
 | ||||||
|   def apply(partyId: String, config: Config, |   def apply(partyId: String, config: Config, | ||||||
|             players: Map[Long, Player], bis: Seq[Loot], loot: Seq[Loot]): Party = { |             players: Map[Long, Player], bis: Seq[Loot], loot: Seq[Loot]): Party = { | ||||||
| @ -51,7 +52,7 @@ object Party { | |||||||
|           .withBiS(bisByPlayer.get(playerId)) |           .withBiS(bisByPlayer.get(playerId)) | ||||||
|           .withLoot(lootByPlayer.get(playerId))) |           .withLoot(lootByPlayer.get(playerId))) | ||||||
|     } |     } | ||||||
|     Party(partyId, config, playersWithItems) |     Party(partyId, getRules(config), playersWithItems) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   def randomPartyId: String = Random.alphanumeric.take(20).mkString |   def randomPartyId: String = Random.alphanumeric.take(20).mkString | ||||||
| @ -104,7 +104,7 @@ object Piece { | |||||||
|       case other => throw new Error(s"Unknown item type $other") |       case other => throw new Error(s"Unknown item type $other") | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   def available: Seq[String] = Seq("weapon", |   lazy val available: Seq[String] = Seq("weapon", | ||||||
|     "head", "body", "hands", "waist", "legs", "feet", |     "head", "body", "hands", "waist", "legs", "feet", | ||||||
|     "ears", "neck", "wrist", "leftRing", "rightRing") |     "ears", "neck", "wrist", "leftRing", "rightRing") | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ case class Player(partyId: String, | |||||||
|                   loot: Seq[Piece], |                   loot: Seq[Piece], | ||||||
|                   link: Option[String] = None, |                   link: Option[String] = None, | ||||||
|                   priority: Int = 0) { |                   priority: Int = 0) { | ||||||
|   require(job != Job.AnyJob, "AnyJob is not allowed") |   require(job ne Job.AnyJob, "AnyJob is not allowed") | ||||||
|  |  | ||||||
|   val playerId: PlayerId = PlayerId(partyId, job, nick) |   val playerId: PlayerId = PlayerId(partyId, job, nick) | ||||||
|   def withBiS(set: Option[BiS]): Player = set match { |   def withBiS(set: Option[BiS]): Player = set match { | ||||||
|  | |||||||
| @ -23,13 +23,13 @@ case class PlayerId(partyId: String, job: Job.Job, nick: String) extends PlayerI | |||||||
| object PlayerId { | object PlayerId { | ||||||
|   def apply(partyId: String, maybeNick: Option[String], maybeJob: Option[String]): Option[PlayerId] = |   def apply(partyId: String, maybeNick: Option[String], maybeJob: Option[String]): Option[PlayerId] = | ||||||
|     (maybeNick, maybeJob) match { |     (maybeNick, maybeJob) match { | ||||||
|       case (Some(nick), Some(job)) => Try(PlayerId(partyId, Job.fromString(job), nick)).toOption |       case (Some(nick), Some(job)) => Try(PlayerId(partyId, Job.withName(job), nick)).toOption | ||||||
|       case _ => None |       case _ => None | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   private val prettyPlayerIdRegex: Regex = "^(.*) \\(([A-Z]{3})\\)$".r |   private val prettyPlayerIdRegex: Regex = "^(.*) \\(([A-Z]{3})\\)$".r | ||||||
|   def apply(partyId: String, player: String): Option[PlayerId] = player match { |   def apply(partyId: String, player: String): Option[PlayerId] = player match { | ||||||
|     case s"${prettyPlayerIdRegex(nick, job)}" => Try(PlayerId(partyId, Job.fromString(job), nick)).toOption |     case s"${prettyPlayerIdRegex(nick, job)}" => Try(PlayerId(partyId, Job.withName(job), nick)).toOption | ||||||
|     case _ => None |     case _ => None | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ package me.arcanis.ffxivbis.service | |||||||
|  |  | ||||||
| import akka.actor.Actor | import akka.actor.Actor | ||||||
| import com.typesafe.scalalogging.StrictLogging | import com.typesafe.scalalogging.StrictLogging | ||||||
| import me.arcanis.ffxivbis.models.{Player, PlayerId} | import me.arcanis.ffxivbis.models.{Party, Player, PlayerId} | ||||||
| import me.arcanis.ffxivbis.storage.DatabaseProfile | import me.arcanis.ffxivbis.storage.DatabaseProfile | ||||||
|  |  | ||||||
| import scala.concurrent.{ExecutionContext, Future} | import scala.concurrent.{ExecutionContext, Future} | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ trait BiSProfile { this: DatabaseProfile => | |||||||
|   import dbConfig.profile.api._ |   import dbConfig.profile.api._ | ||||||
|  |  | ||||||
|   case class BiSRep(playerId: Long, created: Long, piece: String, isTome: Int, job: String) { |   case class BiSRep(playerId: Long, created: Long, piece: String, isTome: Int, job: String) { | ||||||
|     def toLoot: Loot = Loot(playerId, Piece(piece, isTome == 1, Job.fromString(job))) |     def toLoot: Loot = Loot(playerId, Piece(piece, isTome == 1, Job.withName(job))) | ||||||
|   } |   } | ||||||
|   object BiSRep { |   object BiSRep { | ||||||
|     def fromPiece(playerId: Long, piece: Piece) = |     def fromPiece(playerId: Long, piece: Piece) = | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ trait LootProfile { this: DatabaseProfile => | |||||||
|  |  | ||||||
|   case class LootRep(lootId: Option[Long], playerId: Long, created: Long, piece: String, |   case class LootRep(lootId: Option[Long], playerId: Long, created: Long, piece: String, | ||||||
|                      isTome: Int, job: String) { |                      isTome: Int, job: String) { | ||||||
|     def toLoot: Loot = Loot(playerId, Piece(piece, isTome == 1, Job.fromString(job))) |     def toLoot: Loot = Loot(playerId, Piece(piece, isTome == 1, Job.withName(job))) | ||||||
|   } |   } | ||||||
|   object LootRep { |   object LootRep { | ||||||
|     def fromPiece(playerId: Long, piece: Piece) = |     def fromPiece(playerId: Long, piece: Piece) = | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ trait PlayersProfile { this: DatabaseProfile => | |||||||
|   case class PlayerRep(partyId: String, playerId: Option[Long], created: Long, nick: String, |   case class PlayerRep(partyId: String, playerId: Option[Long], created: Long, nick: String, | ||||||
|                        job: String, link: Option[String], priority: Int) { |                        job: String, link: Option[String], priority: Int) { | ||||||
|     def toPlayer: Player = |     def toPlayer: Player = | ||||||
|       Player(partyId, Job.fromString(job), nick, BiS(Seq.empty), List.empty, link, priority) |       Player(partyId, Job.withName(job), nick, BiS(Seq.empty), List.empty, link, priority) | ||||||
|   } |   } | ||||||
|   object PlayerRep { |   object PlayerRep { | ||||||
|     def fromPlayer(player: Player, id: Option[Long]): PlayerRep = |     def fromPlayer(player: Player, id: Option[Long]): PlayerRep = | ||||||
|  | |||||||
							
								
								
									
										55
									
								
								src/test/scala/me/arcanis/ffxivbis/models/BiSTest.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/test/scala/me/arcanis/ffxivbis/models/BiSTest.scala
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | |||||||
|  | package me.arcanis.ffxivbis.models | ||||||
|  |  | ||||||
|  | import me.arcanis.ffxivbis.utils.Compare | ||||||
|  | import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} | ||||||
|  |  | ||||||
|  | class BiSTest extends WordSpecLike with Matchers with BeforeAndAfterAll { | ||||||
|  |  | ||||||
|  |   "bis model" must { | ||||||
|  |  | ||||||
|  |     "build set from list" in { | ||||||
|  |       BiS(Fixtures.bis.pieces) shouldEqual Fixtures.bis | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "has piece" in { | ||||||
|  |       Fixtures.bis.hasPiece(Fixtures.lootBody) shouldEqual true | ||||||
|  |       Fixtures.bis.hasPiece(Fixtures.lootHands) shouldEqual true | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "has upgrade" in { | ||||||
|  |       Fixtures.bis.hasPiece(Fixtures.lootUpgrade) shouldEqual true | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "does not have piece" in { | ||||||
|  |       Fixtures.bis.hasPiece(Fixtures.lootLegs) shouldEqual false | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "create copy with another piece" in { | ||||||
|  |       val bis = BiS(Seq(Fixtures.lootLegs)) | ||||||
|  |       val newBis = bis.withPiece(Fixtures.lootHands) | ||||||
|  |  | ||||||
|  |       newBis.legs shouldEqual Some(Fixtures.lootLegs) | ||||||
|  |       newBis.hands shouldEqual Some(Fixtures.lootHands) | ||||||
|  |       newBis.pieces.length shouldEqual 2 | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "create copy without piece" in { | ||||||
|  |       val bis = BiS(Seq(Fixtures.lootHands, Fixtures.lootLegs)) | ||||||
|  |       val newBis = bis.withoutPiece(Fixtures.lootHands) | ||||||
|  |  | ||||||
|  |       newBis.legs shouldEqual Some(Fixtures.lootLegs) | ||||||
|  |       newBis.hands shouldEqual None | ||||||
|  |       newBis.pieces.length shouldEqual 1 | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "ignore upgrade on modification" in { | ||||||
|  |       Fixtures.bis.withPiece(Fixtures.lootUpgrade) shouldEqual Fixtures.bis | ||||||
|  |       Fixtures.bis.withoutPiece(Fixtures.lootUpgrade) shouldEqual Fixtures.bis | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "return upgrade list" in { | ||||||
|  |       Compare.mapEquals(Fixtures.bis.upgrades, Map[PieceUpgrade, Int](BodyUpgrade -> 2, AccessoryUpgrade -> 4)) shouldEqual true | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,7 +1,5 @@ | |||||||
| package me.arcanis.ffxivbis.models | package me.arcanis.ffxivbis.models | ||||||
|  |  | ||||||
| import me.arcanis.ffxivbis.service.Party |  | ||||||
|  |  | ||||||
| object Fixtures { | object Fixtures { | ||||||
|   lazy val bis: BiS = BiS( |   lazy val bis: BiS = BiS( | ||||||
|     Seq( |     Seq( | ||||||
| @ -22,9 +20,15 @@ object Fixtures { | |||||||
|  |  | ||||||
|   lazy val link: String = "https://ffxiv.ariyala.com/19V5R" |   lazy val link: String = "https://ffxiv.ariyala.com/19V5R" | ||||||
|  |  | ||||||
|   lazy val lootBody: Piece = Body(isTome = false, Job.DNC) |   lazy val lootWeapon: Piece = Weapon(isTome = true, Job.AnyJob) | ||||||
|   lazy val lootHands: Piece = Hands(isTome = true, Job.DNC) |   lazy val lootBody: Piece = Body(isTome = false, Job.AnyJob) | ||||||
|   lazy val lootLegs: Piece = Legs(isTome = false, Job.DNC) |   lazy val lootHands: Piece = Hands(isTome = true, Job.AnyJob) | ||||||
|  |   lazy val lootWaist: Piece = Waist(isTome = true, Job.AnyJob) | ||||||
|  |   lazy val lootLegs: Piece = Legs(isTome = false, Job.AnyJob) | ||||||
|  |   lazy val lootEars: Piece = Ears(isTome = false, Job.AnyJob) | ||||||
|  |   lazy val lootRing: Piece = Ring(isTome = true, Job.AnyJob) | ||||||
|  |   lazy val lootLeftRing: Piece = Ring(isTome = true, Job.AnyJob, "leftRing") | ||||||
|  |   lazy val lootRightRing: Piece = Ring(isTome = true, Job.AnyJob, "rightRing") | ||||||
|   lazy val lootUpgrade: Piece = BodyUpgrade |   lazy val lootUpgrade: Piece = BodyUpgrade | ||||||
|   lazy val loot: Seq[Piece] = Seq(lootBody, lootHands, lootLegs, lootUpgrade) |   lazy val loot: Seq[Piece] = Seq(lootBody, lootHands, lootLegs, lootUpgrade) | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								src/test/scala/me/arcanis/ffxivbis/models/JobTest.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/test/scala/me/arcanis/ffxivbis/models/JobTest.scala
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | package me.arcanis.ffxivbis.models | ||||||
|  |  | ||||||
|  | import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} | ||||||
|  |  | ||||||
|  | class JobTest extends WordSpecLike with Matchers with BeforeAndAfterAll { | ||||||
|  |  | ||||||
|  |   "job model" must { | ||||||
|  |  | ||||||
|  |     "create job from string" in { | ||||||
|  |       Job.jobs.foreach { job => | ||||||
|  |         Job.withName(job.toString) shouldEqual job | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "return AnyJob on unknown job" in { | ||||||
|  |       Job.withName("random string") shouldEqual Job.AnyJob | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "equal AnyJob to others" in { | ||||||
|  |       Job.jobs.foreach { job => | ||||||
|  |         Job.AnyJob shouldBe job | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										51
									
								
								src/test/scala/me/arcanis/ffxivbis/models/PartyTest.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/test/scala/me/arcanis/ffxivbis/models/PartyTest.scala
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | package me.arcanis.ffxivbis.models | ||||||
|  |  | ||||||
|  | import me.arcanis.ffxivbis.utils.Compare | ||||||
|  | import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} | ||||||
|  |  | ||||||
|  | class PartyTest extends WordSpecLike with Matchers with BeforeAndAfterAll { | ||||||
|  |  | ||||||
|  |   private val party = | ||||||
|  |     Party(Fixtures.partyId, Seq.empty, Map(Fixtures.playerEmpty.playerId -> Fixtures.playerEmpty)) | ||||||
|  |  | ||||||
|  |   "party model" must { | ||||||
|  |  | ||||||
|  |     "accept player with same party id" in { | ||||||
|  |       noException should be thrownBy | ||||||
|  |         Party(Fixtures.partyId, Seq.empty, Map(Fixtures.playerEmpty.playerId -> Fixtures.playerEmpty)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "fail on multiple party ids" in { | ||||||
|  |       val anotherPlayer = Fixtures.playerEmpty.copy(partyId = Fixtures.partyId2) | ||||||
|  |  | ||||||
|  |       an [IllegalArgumentException] should be thrownBy | ||||||
|  |         Party(Fixtures.partyId, Seq.empty, Map(anotherPlayer.playerId -> anotherPlayer)) | ||||||
|  |       an [IllegalArgumentException] should be thrownBy | ||||||
|  |         Party(Fixtures.partyId, Seq.empty, Map(Fixtures.playerEmpty.playerId -> Fixtures.playerEmpty, anotherPlayer.playerId -> anotherPlayer)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "return player list" in { | ||||||
|  |       Compare.seqEquals(party.getPlayers, Seq(Fixtures.playerEmpty)) shouldEqual true | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "return player" in { | ||||||
|  |       party.player(Fixtures.playerEmpty.playerId) shouldEqual Some(Fixtures.playerEmpty) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "return empty on unknown player" in { | ||||||
|  |       party.player(Fixtures.playerEmpty.copy(partyId = Fixtures.partyId2).playerId) shouldEqual None | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "add new player" in { | ||||||
|  |       val newParty = Party(Fixtures.partyId, Seq.empty, Map.empty) | ||||||
|  |       newParty.withPlayer(Fixtures.playerEmpty) shouldEqual party | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "reject player with another party id" in { | ||||||
|  |       val anotherPlayer = Fixtures.playerEmpty.copy(partyId = Fixtures.partyId2) | ||||||
|  |  | ||||||
|  |       party.withPlayer(anotherPlayer) shouldEqual party | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								src/test/scala/me/arcanis/ffxivbis/models/PieceTest.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/test/scala/me/arcanis/ffxivbis/models/PieceTest.scala
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | package me.arcanis.ffxivbis.models | ||||||
|  |  | ||||||
|  | import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} | ||||||
|  |  | ||||||
|  | class PieceTest extends WordSpecLike with Matchers with BeforeAndAfterAll { | ||||||
|  |  | ||||||
|  |   "piece model" must { | ||||||
|  |  | ||||||
|  |     "convert `isTome` property to string" in { | ||||||
|  |       Fixtures.lootBody.isTomeToString shouldEqual "no" | ||||||
|  |       Fixtures.lootHands.isTomeToString shouldEqual "yes" | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "return upgrade" in { | ||||||
|  |       Fixtures.lootWeapon.upgrade shouldEqual Some(WeaponUpgrade) | ||||||
|  |       Fixtures.lootBody.upgrade shouldEqual None | ||||||
|  |       Fixtures.lootHands.upgrade shouldEqual Some(BodyUpgrade) | ||||||
|  |       Fixtures.lootWaist.upgrade shouldEqual Some(AccessoryUpgrade) | ||||||
|  |       Fixtures.lootLegs.upgrade shouldEqual None | ||||||
|  |       Fixtures.lootEars.upgrade shouldEqual None | ||||||
|  |       Fixtures.lootLeftRing.upgrade shouldEqual Some(AccessoryUpgrade) | ||||||
|  |       Fixtures.lootRightRing.upgrade shouldEqual Some(AccessoryUpgrade) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "build piece from string" in { | ||||||
|  |       Fixtures.bis.pieces.foreach { piece => | ||||||
|  |         Piece(piece.piece, piece.isTome, piece.job) shouldEqual piece | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								src/test/scala/me/arcanis/ffxivbis/models/PlayerIdTest.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/test/scala/me/arcanis/ffxivbis/models/PlayerIdTest.scala
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | package me.arcanis.ffxivbis.models | ||||||
|  |  | ||||||
|  | import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} | ||||||
|  |  | ||||||
|  | class PlayerIdTest extends WordSpecLike with Matchers with BeforeAndAfterAll { | ||||||
|  |  | ||||||
|  |   "player id model" must { | ||||||
|  |  | ||||||
|  |     "be parsed from string" in { | ||||||
|  |       PlayerId(Fixtures.partyId, Fixtures.playerEmpty.playerId.toString) shouldEqual Some(Fixtures.playerEmpty.playerId) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								src/test/scala/me/arcanis/ffxivbis/models/PlayerTest.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/test/scala/me/arcanis/ffxivbis/models/PlayerTest.scala
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | package me.arcanis.ffxivbis.models | ||||||
|  |  | ||||||
|  | import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} | ||||||
|  |  | ||||||
|  | class PlayerTest extends WordSpecLike with Matchers with BeforeAndAfterAll { | ||||||
|  |  | ||||||
|  |   "player model" must { | ||||||
|  |  | ||||||
|  |     "add best in slot set" in { | ||||||
|  |       Fixtures.playerEmpty.withBiS(Some(Fixtures.bis)).bis shouldEqual Fixtures.bis | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "add loot" in { | ||||||
|  |       Fixtures.playerEmpty.withLoot(Some(Fixtures.loot)).loot shouldEqual Fixtures.loot | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								src/test/scala/me/arcanis/ffxivbis/models/UserTest.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/test/scala/me/arcanis/ffxivbis/models/UserTest.scala
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | package me.arcanis.ffxivbis.models | ||||||
|  |  | ||||||
|  | import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} | ||||||
|  |  | ||||||
|  | class UserTest extends WordSpecLike with Matchers with BeforeAndAfterAll { | ||||||
|  |  | ||||||
|  |   "user model" must { | ||||||
|  |  | ||||||
|  |     "verify password" in { | ||||||
|  |       Fixtures.userAdmin.verify(Fixtures.userPassword) shouldEqual true | ||||||
|  |       Fixtures.userAdmin.verify(Fixtures.userPassword2) shouldEqual false | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     "verify scope" in { | ||||||
|  |       Permission.values.foreach { permission => | ||||||
|  |         Fixtures.userAdmin.verityScope(permission) shouldEqual true | ||||||
|  |       } | ||||||
|  |       Permission.values.foreach { permission => | ||||||
|  |         Fixtures.userGet.verityScope(permission) shouldEqual (permission == Permission.get) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -2,7 +2,7 @@ package me.arcanis.ffxivbis.service | |||||||
|  |  | ||||||
| import akka.actor.ActorSystem | import akka.actor.ActorSystem | ||||||
| import akka.testkit.{ImplicitSender, TestKit} | import akka.testkit.{ImplicitSender, TestKit} | ||||||
| import me.arcanis.ffxivbis.models.{Fixtures, Settings} | import me.arcanis.ffxivbis.models.{Fixtures, Party, Settings} | ||||||
| import me.arcanis.ffxivbis.storage.Migration | import me.arcanis.ffxivbis.storage.Migration | ||||||
| import me.arcanis.ffxivbis.utils.Compare | import me.arcanis.ffxivbis.utils.Compare | ||||||
| import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} | import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} | ||||||
|  | |||||||
| @ -1,6 +1,11 @@ | |||||||
| package me.arcanis.ffxivbis.utils | package me.arcanis.ffxivbis.utils | ||||||
|  |  | ||||||
| object Compare { | object Compare { | ||||||
|  |   def mapEquals[K, T](left: Map[K, T], right: Map[K, T]): Boolean = | ||||||
|  |     left.forall { | ||||||
|  |       case (key, value) => right.contains(key) && right(key) == value | ||||||
|  |     } | ||||||
|  |  | ||||||
|   def seqEquals[T](left: Seq[T], right: Seq[T]): Boolean = |   def seqEquals[T](left: Seq[T], right: Seq[T]): Boolean = | ||||||
|     left.groupBy(identity).view.mapValues(_.size).forall { |     left.groupBy(identity).view.mapValues(_.size).forall { | ||||||
|       case (key, count) => right.count(_ == key) == count |       case (key, count) => right.count(_ == key) == count | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user