diff --git a/src/main/resources/html/bis.html b/src/main/resources/html/bis.html
deleted file mode 100644
index e69de29..0000000
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/PlayerHelper.scala b/src/main/scala/me/arcanis/ffxivbis/http/PlayerHelper.scala
index 50dfc46..85e46cf 100644
--- a/src/main/scala/me/arcanis/ffxivbis/http/PlayerHelper.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/http/PlayerHelper.scala
@@ -11,8 +11,7 @@ package me.arcanis.ffxivbis.http
import akka.actor.ActorRef
import akka.pattern.ask
import akka.util.Timeout
-import me.arcanis.ffxivbis.models.{Player, PlayerId}
-import me.arcanis.ffxivbis.service.Party
+import me.arcanis.ffxivbis.models.{Party, Player, PlayerId}
import me.arcanis.ffxivbis.service.impl.{DatabaseBiSHandler, DatabasePartyHandler}
import scala.concurrent.{ExecutionContext, Future}
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PieceResponse.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PieceResponse.scala
index f4aa9f7..65ebfe5 100644
--- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PieceResponse.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PieceResponse.scala
@@ -15,7 +15,7 @@ case class PieceResponse(
@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 = "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 {
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PlayerIdResponse.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PlayerIdResponse.scala
index f6a9202..0dc3353 100644
--- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PlayerIdResponse.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PlayerIdResponse.scala
@@ -16,5 +16,5 @@ case class PlayerIdResponse(
@Schema(description = "job name", required = true, example = "DNC") job: String,
@Schema(description = "player nick name", required = true, example = "Siuan Sanche") nick: String) {
def withPartyId(partyId: String): PlayerId =
- PlayerId(partyId, Job.fromString(job), nick)
+ PlayerId(partyId, Job.withName(job), nick)
}
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PlayerResponse.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PlayerResponse.scala
index d993ef9..54b2db6 100644
--- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PlayerResponse.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PlayerResponse.scala
@@ -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 = "player loot priority") priority: Option[Int]) {
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),
link, priority.getOrElse(0))
}
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/view/IndexView.scala b/src/main/scala/me/arcanis/ffxivbis/http/view/IndexView.scala
index 5399b9f..1c52c2f 100644
--- a/src/main/scala/me/arcanis/ffxivbis/http/view/IndexView.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/http/view/IndexView.scala
@@ -14,8 +14,7 @@ import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server._
import akka.util.Timeout
import me.arcanis.ffxivbis.http.UserHelper
-import me.arcanis.ffxivbis.models.{Permission, User}
-import me.arcanis.ffxivbis.service.Party
+import me.arcanis.ffxivbis.models.{Party, Permission, User}
class IndexView(storage: ActorRef)(implicit timeout: Timeout)
extends UserHelper(storage) {
diff --git a/src/main/scala/me/arcanis/ffxivbis/http/view/PlayerView.scala b/src/main/scala/me/arcanis/ffxivbis/http/view/PlayerView.scala
index bad264b..b7e8bd9 100644
--- a/src/main/scala/me/arcanis/ffxivbis/http/view/PlayerView.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/http/view/PlayerView.scala
@@ -92,7 +92,7 @@ object PlayerView {
form(action:=s"/party/$partyId/players", method:="post")(
input(name:="nick", id:="nick", placeholder:="nick", title:="nick", `type`:="nick"),
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:="prioiry", id:="priority", placeholder:="priority", title:="priority", `type`:="number", value:="0"),
input(name:="action", id:="action", `type`:="hidden", value:="add"),
diff --git a/src/main/scala/me/arcanis/ffxivbis/models/BiS.scala b/src/main/scala/me/arcanis/ffxivbis/models/BiS.scala
index 7ed3570..38dc7d8 100644
--- a/src/main/scala/me/arcanis/ffxivbis/models/BiS.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/models/BiS.scala
@@ -76,5 +76,5 @@ object BiS {
def apply(): BiS = BiS(Seq.empty)
def apply(pieces: Seq[Piece]): BiS =
- BiS(pieces.map { piece => piece.piece -> Some(piece) }.toMap)
+ BiS(pieces.map(piece => piece.piece -> Some(piece)).toMap)
}
diff --git a/src/main/scala/me/arcanis/ffxivbis/models/Job.scala b/src/main/scala/me/arcanis/ffxivbis/models/Job.scala
index 01c68e7..beaae30 100644
--- a/src/main/scala/me/arcanis/ffxivbis/models/Job.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/models/Job.scala
@@ -9,65 +9,95 @@
package me.arcanis.ffxivbis.models
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 {
- override def equals(obj: Any): Boolean = obj match {
- case Job => true
- case _ => false
- }
+ val leftSide: LeftSide = null
+ val rightSide: RightSide = null
}
- case object PLD extends Job
- case object WAR extends Job
- case object DRK extends Job
- 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 Casters extends Job {
+ val leftSide: LeftSide = BodyCasters
+ val rightSide: RightSide = AccessoriesInt
}
+ 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)
}
diff --git a/src/main/scala/me/arcanis/ffxivbis/service/Party.scala b/src/main/scala/me/arcanis/ffxivbis/models/Party.scala
similarity index 79%
rename from src/main/scala/me/arcanis/ffxivbis/service/Party.scala
rename to src/main/scala/me/arcanis/ffxivbis/models/Party.scala
index fcdeb67..9090f76 100644
--- a/src/main/scala/me/arcanis/ffxivbis/service/Party.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/models/Party.scala
@@ -6,20 +6,18 @@
*
* 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.scalalogging.StrictLogging
-import me.arcanis.ffxivbis.models.{BiS, Loot, Piece, Player, PlayerId}
+import me.arcanis.ffxivbis.service.LootSelector
import scala.jdk.CollectionConverters._
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 {
-
- private val rules =
- config.getStringList("me.arcanis.ffxivbis.settings.priority").asScala.toSeq
+ require(players.keys.forall(_.partyId == partyId), "party id must be same")
def getPlayers: Seq[Player] = players.values.toSeq
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 {
+ private def getRules(config: Config): Seq[String] =
+ config.getStringList("me.arcanis.ffxivbis.settings.priority").asScala.toSeq
+
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,
players: Map[Long, Player], bis: Seq[Loot], loot: Seq[Loot]): Party = {
@@ -51,7 +52,7 @@ object Party {
.withBiS(bisByPlayer.get(playerId))
.withLoot(lootByPlayer.get(playerId)))
}
- Party(partyId, config, playersWithItems)
+ Party(partyId, getRules(config), playersWithItems)
}
def randomPartyId: String = Random.alphanumeric.take(20).mkString
diff --git a/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala b/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala
index 73f4ab1..8c235f4 100644
--- a/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala
@@ -104,7 +104,7 @@ object Piece {
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",
"ears", "neck", "wrist", "leftRing", "rightRing")
}
diff --git a/src/main/scala/me/arcanis/ffxivbis/models/Player.scala b/src/main/scala/me/arcanis/ffxivbis/models/Player.scala
index bc985a8..acef4c1 100644
--- a/src/main/scala/me/arcanis/ffxivbis/models/Player.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/models/Player.scala
@@ -15,7 +15,7 @@ case class Player(partyId: String,
loot: Seq[Piece],
link: Option[String] = None,
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)
def withBiS(set: Option[BiS]): Player = set match {
diff --git a/src/main/scala/me/arcanis/ffxivbis/models/PlayerId.scala b/src/main/scala/me/arcanis/ffxivbis/models/PlayerId.scala
index 876e6c2..6e2ad7b 100644
--- a/src/main/scala/me/arcanis/ffxivbis/models/PlayerId.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/models/PlayerId.scala
@@ -23,13 +23,13 @@ case class PlayerId(partyId: String, job: Job.Job, nick: String) extends PlayerI
object PlayerId {
def apply(partyId: String, maybeNick: Option[String], maybeJob: Option[String]): Option[PlayerId] =
(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
}
private val prettyPlayerIdRegex: Regex = "^(.*) \\(([A-Z]{3})\\)$".r
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
}
}
diff --git a/src/main/scala/me/arcanis/ffxivbis/service/Database.scala b/src/main/scala/me/arcanis/ffxivbis/service/Database.scala
index 79f9060..faa0db2 100644
--- a/src/main/scala/me/arcanis/ffxivbis/service/Database.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/service/Database.scala
@@ -10,7 +10,7 @@ package me.arcanis.ffxivbis.service
import akka.actor.Actor
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 scala.concurrent.{ExecutionContext, Future}
diff --git a/src/main/scala/me/arcanis/ffxivbis/storage/BiSProfile.scala b/src/main/scala/me/arcanis/ffxivbis/storage/BiSProfile.scala
index eaceabb..580fef1 100644
--- a/src/main/scala/me/arcanis/ffxivbis/storage/BiSProfile.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/storage/BiSProfile.scala
@@ -17,7 +17,7 @@ trait BiSProfile { this: DatabaseProfile =>
import dbConfig.profile.api._
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 {
def fromPiece(playerId: Long, piece: Piece) =
diff --git a/src/main/scala/me/arcanis/ffxivbis/storage/LootProfile.scala b/src/main/scala/me/arcanis/ffxivbis/storage/LootProfile.scala
index b395872..03de0b0 100644
--- a/src/main/scala/me/arcanis/ffxivbis/storage/LootProfile.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/storage/LootProfile.scala
@@ -18,7 +18,7 @@ trait LootProfile { this: DatabaseProfile =>
case class LootRep(lootId: Option[Long], 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 LootRep {
def fromPiece(playerId: Long, piece: Piece) =
diff --git a/src/main/scala/me/arcanis/ffxivbis/storage/PlayersProfile.scala b/src/main/scala/me/arcanis/ffxivbis/storage/PlayersProfile.scala
index 6fd4079..c723e8a 100644
--- a/src/main/scala/me/arcanis/ffxivbis/storage/PlayersProfile.scala
+++ b/src/main/scala/me/arcanis/ffxivbis/storage/PlayersProfile.scala
@@ -19,7 +19,7 @@ trait PlayersProfile { this: DatabaseProfile =>
case class PlayerRep(partyId: String, playerId: Option[Long], created: Long, nick: String,
job: String, link: Option[String], priority: Int) {
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 {
def fromPlayer(player: Player, id: Option[Long]): PlayerRep =
diff --git a/src/test/scala/me/arcanis/ffxivbis/models/BiSTest.scala b/src/test/scala/me/arcanis/ffxivbis/models/BiSTest.scala
new file mode 100644
index 0000000..cd789ce
--- /dev/null
+++ b/src/test/scala/me/arcanis/ffxivbis/models/BiSTest.scala
@@ -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
+ }
+
+ }
+}
diff --git a/src/test/scala/me/arcanis/ffxivbis/models/Fixtures.scala b/src/test/scala/me/arcanis/ffxivbis/models/Fixtures.scala
index ab09eee..5f79c84 100644
--- a/src/test/scala/me/arcanis/ffxivbis/models/Fixtures.scala
+++ b/src/test/scala/me/arcanis/ffxivbis/models/Fixtures.scala
@@ -1,7 +1,5 @@
package me.arcanis.ffxivbis.models
-import me.arcanis.ffxivbis.service.Party
-
object Fixtures {
lazy val bis: BiS = BiS(
Seq(
@@ -22,9 +20,15 @@ object Fixtures {
lazy val link: String = "https://ffxiv.ariyala.com/19V5R"
- lazy val lootBody: Piece = Body(isTome = false, Job.DNC)
- lazy val lootHands: Piece = Hands(isTome = true, Job.DNC)
- lazy val lootLegs: Piece = Legs(isTome = false, Job.DNC)
+ lazy val lootWeapon: Piece = Weapon(isTome = true, Job.AnyJob)
+ lazy val lootBody: Piece = Body(isTome = false, Job.AnyJob)
+ 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 loot: Seq[Piece] = Seq(lootBody, lootHands, lootLegs, lootUpgrade)
diff --git a/src/test/scala/me/arcanis/ffxivbis/models/JobTest.scala b/src/test/scala/me/arcanis/ffxivbis/models/JobTest.scala
new file mode 100644
index 0000000..981629d
--- /dev/null
+++ b/src/test/scala/me/arcanis/ffxivbis/models/JobTest.scala
@@ -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
+ }
+ }
+
+ }
+}
diff --git a/src/test/scala/me/arcanis/ffxivbis/models/PartyTest.scala b/src/test/scala/me/arcanis/ffxivbis/models/PartyTest.scala
new file mode 100644
index 0000000..4ffba03
--- /dev/null
+++ b/src/test/scala/me/arcanis/ffxivbis/models/PartyTest.scala
@@ -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
+ }
+
+ }
+}
diff --git a/src/test/scala/me/arcanis/ffxivbis/models/PieceTest.scala b/src/test/scala/me/arcanis/ffxivbis/models/PieceTest.scala
new file mode 100644
index 0000000..522fc17
--- /dev/null
+++ b/src/test/scala/me/arcanis/ffxivbis/models/PieceTest.scala
@@ -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
+ }
+ }
+
+ }
+}
diff --git a/src/test/scala/me/arcanis/ffxivbis/models/PlayerIdTest.scala b/src/test/scala/me/arcanis/ffxivbis/models/PlayerIdTest.scala
new file mode 100644
index 0000000..8f3e07f
--- /dev/null
+++ b/src/test/scala/me/arcanis/ffxivbis/models/PlayerIdTest.scala
@@ -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)
+ }
+
+ }
+}
diff --git a/src/test/scala/me/arcanis/ffxivbis/models/PlayerTest.scala b/src/test/scala/me/arcanis/ffxivbis/models/PlayerTest.scala
new file mode 100644
index 0000000..6f6035a
--- /dev/null
+++ b/src/test/scala/me/arcanis/ffxivbis/models/PlayerTest.scala
@@ -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
+ }
+
+ }
+}
diff --git a/src/test/scala/me/arcanis/ffxivbis/models/UserTest.scala b/src/test/scala/me/arcanis/ffxivbis/models/UserTest.scala
new file mode 100644
index 0000000..f0911c9
--- /dev/null
+++ b/src/test/scala/me/arcanis/ffxivbis/models/UserTest.scala
@@ -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)
+ }
+ }
+
+ }
+}
diff --git a/src/test/scala/me/arcanis/ffxivbis/service/DatabasePartyHandlerTest.scala b/src/test/scala/me/arcanis/ffxivbis/service/DatabasePartyHandlerTest.scala
index 75c5451..5727f55 100644
--- a/src/test/scala/me/arcanis/ffxivbis/service/DatabasePartyHandlerTest.scala
+++ b/src/test/scala/me/arcanis/ffxivbis/service/DatabasePartyHandlerTest.scala
@@ -2,7 +2,7 @@ package me.arcanis.ffxivbis.service
import akka.actor.ActorSystem
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.utils.Compare
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
diff --git a/src/test/scala/me/arcanis/ffxivbis/utils/Compare.scala b/src/test/scala/me/arcanis/ffxivbis/utils/Compare.scala
index 637aa00..2fb0cea 100644
--- a/src/test/scala/me/arcanis/ffxivbis/utils/Compare.scala
+++ b/src/test/scala/me/arcanis/ffxivbis/utils/Compare.scala
@@ -1,6 +1,11 @@
package me.arcanis.ffxivbis.utils
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 =
left.groupBy(identity).view.mapValues(_.size).forall {
case (key, count) => right.count(_ == key) == count