Merge pull request #157 from Fate-JH/player-avatar-2

The Suppressor Update
This commit is contained in:
Fate-JH 2017-08-25 21:01:19 -04:00 committed by GitHub
commit 3e5e8a2573
135 changed files with 13363 additions and 225 deletions

View file

@ -4,6 +4,7 @@ package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.ImplantType
import scodec.bits._
class AvatarImplantMessageTest extends Specification {

View file

@ -0,0 +1,33 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class FavoritesRequestTest extends Specification {
val stringInfantry = hex"5E 4B00 1187 4500 7800 6100 6D00 7000 6C00 6500"
"decode (for infantry)" in {
PacketCoding.DecodePacket(stringInfantry).require match {
case FavoritesRequest(player_guid, unk, action, line, label) =>
player_guid mustEqual PlanetSideGUID(75)
unk mustEqual 0
action mustEqual FavoritesAction.Save
line mustEqual 1
label.isDefined mustEqual true
label.get mustEqual "Example"
case _ =>
ko
}
}
"encode (for infantry)" in {
val msg = FavoritesRequest(PlanetSideGUID(75), 0, FavoritesAction.Save, 1, Some("Example"))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringInfantry
}
}

View file

@ -391,16 +391,16 @@ class ObjectCreateDetailedMessageTest extends Specification {
false,
RibbonBars()
)
val inv = InventoryItem(ObjectClass.beamer, PlanetSideGUID(76), 0, DetailedWeaponData(4, 8, ObjectClass.energy_cell, PlanetSideGUID(77), 0, DetailedAmmoBoxData(8, 16))) ::
InventoryItem(ObjectClass.suppressor, PlanetSideGUID(78), 2, DetailedWeaponData(4, 8, ObjectClass.bullet_9mm, PlanetSideGUID(79), 0, DetailedAmmoBoxData(8, 25))) ::
InventoryItem(ObjectClass.forceblade, PlanetSideGUID(80), 4, DetailedWeaponData(4, 8, ObjectClass.melee_ammo, PlanetSideGUID(81), 0, DetailedAmmoBoxData(8, 1))) ::
InventoryItem(ObjectClass.locker_container, PlanetSideGUID(82), 5, DetailedAmmoBoxData(8, 1)) ::
InventoryItem(ObjectClass.bullet_9mm, PlanetSideGUID(83), 6, DetailedAmmoBoxData(8, 50)) ::
InventoryItem(ObjectClass.bullet_9mm, PlanetSideGUID(84), 9, DetailedAmmoBoxData(8, 50)) ::
InventoryItem(ObjectClass.bullet_9mm, PlanetSideGUID(85), 12, DetailedAmmoBoxData(8, 50)) ::
InventoryItem(ObjectClass.bullet_9mm_AP, PlanetSideGUID(86), 33, DetailedAmmoBoxData(8, 50)) ::
InventoryItem(ObjectClass.energy_cell, PlanetSideGUID(87), 36, DetailedAmmoBoxData(8, 50)) ::
InventoryItem(ObjectClass.remote_electronics_kit, PlanetSideGUID(88), 39, DetailedREKData(8)) ::
val inv = InventoryItemData(ObjectClass.beamer, PlanetSideGUID(76), 0, DetailedWeaponData(4, 8, ObjectClass.energy_cell, PlanetSideGUID(77), 0, DetailedAmmoBoxData(8, 16))) ::
InventoryItemData(ObjectClass.suppressor, PlanetSideGUID(78), 2, DetailedWeaponData(4, 8, ObjectClass.bullet_9mm, PlanetSideGUID(79), 0, DetailedAmmoBoxData(8, 25))) ::
InventoryItemData(ObjectClass.forceblade, PlanetSideGUID(80), 4, DetailedWeaponData(4, 8, ObjectClass.melee_ammo, PlanetSideGUID(81), 0, DetailedAmmoBoxData(8, 1))) ::
InventoryItemData(ObjectClass.locker_container, PlanetSideGUID(82), 5, DetailedAmmoBoxData(8, 1)) ::
InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(83), 6, DetailedAmmoBoxData(8, 50)) ::
InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(84), 9, DetailedAmmoBoxData(8, 50)) ::
InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(85), 12, DetailedAmmoBoxData(8, 50)) ::
InventoryItemData(ObjectClass.bullet_9mm_AP, PlanetSideGUID(86), 33, DetailedAmmoBoxData(8, 50)) ::
InventoryItemData(ObjectClass.energy_cell, PlanetSideGUID(87), 36, DetailedAmmoBoxData(8, 50)) ::
InventoryItemData(ObjectClass.remote_electronics_kit, PlanetSideGUID(88), 39, DetailedREKData(8)) ::
Nil
val obj = DetailedCharacterData(
app,

View file

@ -1076,9 +1076,9 @@ class ObjectCreateMessageTest extends Specification {
"encode (locker container)" in {
val obj = LockerContainerData(
InventoryData(
InventoryItem(ObjectClass.nano_dispenser, PlanetSideGUID(2935), 0, WeaponData(0x6, 0x0, ObjectClass.armor_canister, PlanetSideGUID(3426), 0, AmmoBoxData())) ::
InventoryItem(ObjectClass.armor_canister, PlanetSideGUID(4090), 45, AmmoBoxData()) ::
InventoryItem(ObjectClass.armor_canister, PlanetSideGUID(3326), 78, AmmoBoxData()) ::
InventoryItemData(ObjectClass.nano_dispenser, PlanetSideGUID(2935), 0, WeaponData(0x6, 0x0, ObjectClass.armor_canister, PlanetSideGUID(3426), 0, AmmoBoxData())) ::
InventoryItemData(ObjectClass.armor_canister, PlanetSideGUID(4090), 45, AmmoBoxData()) ::
InventoryItemData(ObjectClass.armor_canister, PlanetSideGUID(3326), 78, AmmoBoxData()) ::
Nil
)
)
@ -1127,11 +1127,11 @@ class ObjectCreateMessageTest extends Specification {
Some(ImplantEffects.NoEffects),
Some(Cosmetics(true, true, true, true, false)),
InventoryData(
InventoryItem(ObjectClass.plasma_grenade, PlanetSideGUID(3662), 0, WeaponData(0, 0, ObjectClass.plasma_grenade_ammo, PlanetSideGUID(3751), 0, AmmoBoxData())) ::
InventoryItem(ObjectClass.bank, PlanetSideGUID(3908), 1, WeaponData(0, 0, 1, ObjectClass.armor_canister, PlanetSideGUID(4143), 0, AmmoBoxData())) ::
InventoryItem(ObjectClass.mini_chaingun, PlanetSideGUID(4164), 2, WeaponData(0, 0, ObjectClass.bullet_9mm, PlanetSideGUID(3728), 0, AmmoBoxData())) ::
InventoryItem(ObjectClass.phoenix, PlanetSideGUID(3603), 3, WeaponData(0, 0, ObjectClass.phoenix_missile, PlanetSideGUID(3056), 0, AmmoBoxData())) ::
InventoryItem(ObjectClass.chainblade, PlanetSideGUID(4088), 4, WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, AmmoBoxData())) ::
InventoryItemData(ObjectClass.plasma_grenade, PlanetSideGUID(3662), 0, WeaponData(0, 0, ObjectClass.plasma_grenade_ammo, PlanetSideGUID(3751), 0, AmmoBoxData())) ::
InventoryItemData(ObjectClass.bank, PlanetSideGUID(3908), 1, WeaponData(0, 0, 1, ObjectClass.armor_canister, PlanetSideGUID(4143), 0, AmmoBoxData())) ::
InventoryItemData(ObjectClass.mini_chaingun, PlanetSideGUID(4164), 2, WeaponData(0, 0, ObjectClass.bullet_9mm, PlanetSideGUID(3728), 0, AmmoBoxData())) ::
InventoryItemData(ObjectClass.phoenix, PlanetSideGUID(3603), 3, WeaponData(0, 0, ObjectClass.phoenix_missile, PlanetSideGUID(3056), 0, AmmoBoxData())) ::
InventoryItemData(ObjectClass.chainblade, PlanetSideGUID(4088), 4, WeaponData(0, 0, 1, ObjectClass.melee_ammo, PlanetSideGUID(3279), 0, AmmoBoxData())) ::
Nil
),
DrawnSlot.Rifle1

View file

@ -0,0 +1,200 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.definition.converter.{ACEConverter, REKConverter}
import net.psforever.objects._
import net.psforever.objects.definition._
import net.psforever.objects.equipment.CItem.{DeployedItem, Unit}
import net.psforever.objects.equipment._
import net.psforever.objects.inventory.InventoryTile
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.packet.game.objectcreate._
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
import org.specs2.mutable.Specification
import scala.util.Success
class ConverterTest extends Specification {
"AmmoBox" should {
val bullet_9mm = AmmoBoxDefinition(28)
bullet_9mm.Capacity = 50
"convert to packet" in {
val obj = AmmoBox(bullet_9mm)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedAmmoBoxData(8, 50)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual AmmoBoxData()
case _ =>
ko
}
}
}
"Tool" should {
"convert to packet" in {
val tdef = ToolDefinition(1076)
tdef.Size = EquipmentSize.Rifle
tdef.AmmoTypes += Ammo.shotgun_shell
tdef.AmmoTypes += Ammo.shotgun_shell_AP
tdef.FireModes += new FireModeDefinition
tdef.FireModes.head.AmmoTypeIndices += 0
tdef.FireModes.head.AmmoTypeIndices += 1
tdef.FireModes.head.AmmoSlotIndex = 0
val obj : Tool = Tool(tdef)
val box = AmmoBox(PlanetSideGUID(90), new AmmoBoxDefinition(Ammo.shotgun_shell.id))
obj.AmmoSlots.head.Box = box
obj.AmmoSlots.head.Magazine = 30
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedWeaponData(4,8, Ammo.shotgun_shell.id, PlanetSideGUID(90), 0, DetailedAmmoBoxData(8, 30))
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual WeaponData(4,8, 0, Ammo.shotgun_shell.id, PlanetSideGUID(90), 0, AmmoBoxData())
case _ =>
ko
}
}
}
"Kit" should {
"convert to packet" in {
val kdef = KitDefinition(Kits.medkit)
val obj = Kit(PlanetSideGUID(90), kdef)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedAmmoBoxData(0, 1)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual AmmoBoxData()
case _ =>
ko
}
}
"ConstructionItem" should {
"convert to packet" in {
val cdef = ConstructionItemDefinition(Unit.advanced_ace)
cdef.Modes += DeployedItem.tank_traps
cdef.Modes += DeployedItem.portable_manned_turret_tr
cdef.Modes += DeployedItem.deployable_shield_generator
cdef.Tile = InventoryTile.Tile63
cdef.Packet = new ACEConverter()
val obj = ConstructionItem(PlanetSideGUID(90), cdef)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedACEData(0)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual ACEData(0,0)
case _ =>
ko
}
}
}
}
"SimpleItem" should {
"convert to packet" in {
val sdef = SimpleItemDefinition(SItem.remote_electronics_kit)
sdef.Packet = new REKConverter()
val obj = SimpleItem(PlanetSideGUID(90), sdef)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedREKData(8)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual REKData(8,0)
case _ =>
ko
}
}
}
"Player" should {
"convert to packet" in {
/*
Create an AmmoBoxDefinition with which to build two AmmoBoxes
Create a ToolDefinition with which to create a Tool
Load one of the AmmoBoxes into that Tool
Create a Player
Give the Player's Holster (2) the Tool
Place the remaining AmmoBox into the Player's inventory in the third slot (8)
*/
val bullet_9mm = AmmoBoxDefinition(28)
bullet_9mm.Capacity = 50
val box1 = AmmoBox(PlanetSideGUID(90), bullet_9mm)
val box2 = AmmoBox(PlanetSideGUID(91), bullet_9mm)
val tdef = ToolDefinition(1076)
tdef.Name = "sample_weapon"
tdef.Size = EquipmentSize.Rifle
tdef.AmmoTypes += Ammo.bullet_9mm
tdef.FireModes += new FireModeDefinition
tdef.FireModes.head.AmmoTypeIndices += 0
tdef.FireModes.head.AmmoSlotIndex = 0
tdef.FireModes.head.Magazine = 18
val tool = Tool(PlanetSideGUID(92), tdef)
tool.AmmoSlots.head.Box = box1
val obj = Player(PlanetSideGUID(93), "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Slot(2).Equipment = tool
obj.Inventory += 8 -> box2
obj.Definition.Packet.DetailedConstructorData(obj).isSuccess mustEqual true
ok //TODO write more of this test
}
}
"Vehicle" should {
"convert to packet" in {
val hellfire_ammo = AmmoBoxDefinition(Ammo.hellfire_ammo.id)
val fury_weapon_systema_def = ToolDefinition(ObjectClass.fury_weapon_systema)
fury_weapon_systema_def.Size = EquipmentSize.VehicleWeapon
fury_weapon_systema_def.AmmoTypes += Ammo.hellfire_ammo
fury_weapon_systema_def.FireModes += new FireModeDefinition
fury_weapon_systema_def.FireModes.head.AmmoTypeIndices += 0
fury_weapon_systema_def.FireModes.head.AmmoSlotIndex = 0
fury_weapon_systema_def.FireModes.head.Magazine = 2
val fury_def = VehicleDefinition(ObjectClass.fury)
fury_def.Seats += 0 -> new SeatDefinition()
fury_def.Seats(0).Bailable = true
fury_def.Seats(0).ControlledWeapon = Some(1)
fury_def.MountPoints += 0 -> 0
fury_def.MountPoints += 2 -> 0
fury_def.Weapons += 1 -> fury_weapon_systema_def
fury_def.TrunkSize = InventoryTile(11, 11)
fury_def.TrunkOffset = 30
val hellfire_ammo_box = AmmoBox(PlanetSideGUID(432), hellfire_ammo)
val fury = Vehicle(PlanetSideGUID(413), fury_def)
fury.Faction = PlanetSideEmpire.VS
fury.Position = Vector3(3674.8438f, 2732f, 91.15625f)
fury.Orientation = Vector3(0.0f, 0.0f, 90.0f)
fury.WeaponControlledFromSeat(0).get.GUID = PlanetSideGUID(400)
fury.WeaponControlledFromSeat(0).get.AmmoSlots.head.Box = hellfire_ammo_box
fury.Definition.Packet.ConstructorData(fury).isSuccess mustEqual true
ok //TODO write more of this test
}
}
}

View file

@ -0,0 +1,83 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.PlanetSideGameObject
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.entity.NoGUIDException
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types.Vector3
import org.specs2.mutable._
class EntityTest extends Specification {
//both WorldEntity and IdentifiableEntity are components of PlanetSideGameObject
private class EntityTestClass extends PlanetSideGameObject {
def Definition : ObjectDefinition = new ObjectDefinition(0) { }
}
"SimpleWorldEntity" should {
"construct" in {
new EntityTestClass()
ok
}
"initialize" in {
val obj : EntityTestClass = new EntityTestClass()
obj.Position mustEqual Vector3(0f, 0f, 0f)
obj.Orientation mustEqual Vector3(0f, 0f, 0f)
obj.Velocity mustEqual None
}
"mutate and access" in {
val obj : EntityTestClass = new EntityTestClass
obj.Position = Vector3(1f, 1f, 1f)
obj.Orientation = Vector3(2f, 2f, 2f)
obj.Velocity = Vector3(3f, 3f, 3f)
obj.Position mustEqual Vector3(1f, 1f, 1f)
obj.Orientation mustEqual Vector3(2f, 2f, 2f)
obj.Velocity mustEqual Some(Vector3(3f, 3f, 3f))
}
"clamp Orientation" in {
val obj : EntityTestClass = new EntityTestClass
obj.Orientation = Vector3(-1f, 361f, -0f)
obj.Orientation mustEqual Vector3(359f, 1f, 0f)
}
}
"IdentifiableEntity" should {
"construct" in {
new EntityTestClass()
ok
}
"error while unset" in {
val obj : EntityTestClass = new EntityTestClass
obj.GUID must throwA[NoGUIDException]
}
"work after mutation" in {
val obj : EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.GUID mustEqual PlanetSideGUID(1051)
}
"work after multiple mutations" in {
val obj : EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.GUID mustEqual PlanetSideGUID(1051)
obj.GUID = PlanetSideGUID(30052)
obj.GUID mustEqual PlanetSideGUID(30052)
obj.GUID = PlanetSideGUID(62)
obj.GUID mustEqual PlanetSideGUID(62)
}
"invalidate and resume error" in {
val obj : EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.GUID mustEqual PlanetSideGUID(1051)
obj.Invalidate()
obj.GUID must throwA[NoGUIDException]
}
}
}

View file

@ -0,0 +1,258 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects._
import net.psforever.objects.definition._
import net.psforever.objects.equipment.CItem.{DeployedItem, Unit}
import net.psforever.objects.equipment._
import net.psforever.objects.inventory.InventoryTile
import net.psforever.objects.GlobalDefinitions._
import org.specs2.mutable._
class EquipmentTest extends Specification {
"AmmoBox" should {
"define" in {
val obj = AmmoBoxDefinition(86)
obj.Capacity = 300
obj.Tile = InventoryTile.Tile44
obj.AmmoType mustEqual Ammo.aphelion_immolation_cannon_ammo
obj.Capacity mustEqual 300
obj.Tile.width mustEqual InventoryTile.Tile44.width
obj.Tile.height mustEqual InventoryTile.Tile44.height
obj.ObjectId mustEqual 86
}
"construct" in {
val obj = AmmoBox(bullet_9mm)
obj.AmmoType mustEqual Ammo.bullet_9mm
obj.Capacity mustEqual 50
}
"construct (2)" in {
val obj = AmmoBox(bullet_9mm, 150)
obj.AmmoType mustEqual Ammo.bullet_9mm
obj.Capacity mustEqual 150
}
"vary capacity" in {
val obj = AmmoBox(bullet_9mm, 0)
obj.Capacity mustEqual 1 //can not be initialized to 0
obj.Capacity = 75
obj.Capacity mustEqual 75
}
"limit capacity" in {
val obj = AmmoBox(bullet_9mm)
obj.Capacity mustEqual 50
obj.Capacity = -1
obj.Capacity mustEqual 0
obj.Capacity = 65536
obj.Capacity mustEqual 65535
}
}
"Tool" should {
"define" in {
val obj = ToolDefinition(1076)
obj.Name = "sample_weapon"
obj.Size = EquipmentSize.Rifle
obj.AmmoTypes += Ammo.shotgun_shell
obj.AmmoTypes += Ammo.shotgun_shell_AP
obj.FireModes += new FireModeDefinition
obj.FireModes.head.AmmoTypeIndices += 0
obj.FireModes.head.AmmoTypeIndices += 1
obj.FireModes.head.AmmoSlotIndex = 0
obj.FireModes.head.Magazine = 18
obj.FireModes.head.ResetAmmoIndexOnSwap = true
obj.FireModes += new FireModeDefinition
obj.FireModes(1).AmmoTypeIndices += 0
obj.FireModes(1).AmmoTypeIndices += 1
obj.FireModes(1).AmmoSlotIndex = 1
obj.FireModes(1).Chamber = 3
obj.FireModes(1).Magazine = 18
obj.Tile = InventoryTile.Tile93
obj.ObjectId mustEqual 1076
obj.Name mustEqual "sample_weapon"
obj.AmmoTypes.head mustEqual Ammo.shotgun_shell
obj.AmmoTypes(1) mustEqual Ammo.shotgun_shell_AP
obj.FireModes.head.AmmoTypeIndices.head mustEqual 0
obj.FireModes.head.AmmoTypeIndices(1) mustEqual 1
obj.FireModes.head.AmmoSlotIndex mustEqual 0
obj.FireModes.head.Chamber mustEqual 1
obj.FireModes.head.Magazine mustEqual 18
obj.FireModes.head.ResetAmmoIndexOnSwap mustEqual true
obj.FireModes(1).AmmoTypeIndices.head mustEqual 0
obj.FireModes(1).AmmoTypeIndices(1) mustEqual 1
obj.FireModes(1).AmmoSlotIndex mustEqual 1
obj.FireModes(1).Chamber mustEqual 3
obj.FireModes(1).Magazine mustEqual 18
obj.FireModes(1).ResetAmmoIndexOnSwap mustEqual false
obj.Tile.width mustEqual InventoryTile.Tile93.width
obj.Tile.height mustEqual InventoryTile.Tile93.height
}
"construct" in {
val obj : Tool = Tool(fury_weapon_systema)
obj.Definition.ObjectId mustEqual fury_weapon_systema.ObjectId
}
"fire mode" in {
//explanation: fury_weapon_systema has one fire mode and that fire mode is our only option
val obj : Tool = Tool(fury_weapon_systema)
obj.Magazine = obj.MaxMagazine
obj.Magazine mustEqual obj.Definition.FireModes.head.Magazine
//fmode = 0
obj.FireModeIndex mustEqual 0
obj.FireMode.Magazine mustEqual 2
obj.AmmoType mustEqual Ammo.hellfire_ammo
//fmode -> 1 (0)
obj.FireModeIndex = 1
obj.FireModeIndex mustEqual 0
obj.FireMode.Magazine mustEqual 2
obj.AmmoType mustEqual Ammo.hellfire_ammo
}
"multiple fire modes" in {
//explanation: sample_weapon has two fire modes; adjusting the FireMode changes between them
val tdef = ToolDefinition(1076)
tdef.Size = EquipmentSize.Rifle
tdef.AmmoTypes += Ammo.shotgun_shell
tdef.AmmoTypes += Ammo.shotgun_shell_AP
tdef.FireModes += new FireModeDefinition
tdef.FireModes.head.AmmoTypeIndices += 0
tdef.FireModes.head.AmmoSlotIndex = 0
tdef.FireModes.head.Magazine = 9
tdef.FireModes += new FireModeDefinition
tdef.FireModes(1).AmmoTypeIndices += 1
tdef.FireModes(1).AmmoSlotIndex = 1
tdef.FireModes(1).Magazine = 18
val obj : Tool = Tool(tdef)
//fmode = 0
obj.FireModeIndex mustEqual 0
obj.FireMode.Magazine mustEqual 9
obj.AmmoType mustEqual Ammo.shotgun_shell
//fmode -> 1
obj.NextFireMode
obj.FireModeIndex mustEqual 1
obj.FireMode.Magazine mustEqual 18
obj.AmmoType mustEqual Ammo.shotgun_shell_AP
//fmode -> 0
obj.NextFireMode
obj.FireModeIndex mustEqual 0
obj.FireMode.Magazine mustEqual 9
obj.AmmoType mustEqual Ammo.shotgun_shell
}
"multiple types of ammunition" in {
//explanation: obj has one fire mode and two ammunitions; adjusting the AmmoType changes between them
val tdef = ToolDefinition(1076)
tdef.Size = EquipmentSize.Rifle
tdef.AmmoTypes += Ammo.shotgun_shell
tdef.AmmoTypes += Ammo.shotgun_shell_AP
tdef.FireModes += new FireModeDefinition
tdef.FireModes.head.AmmoTypeIndices += 0
tdef.FireModes.head.AmmoTypeIndices += 1
tdef.FireModes.head.AmmoSlotIndex = 0
val obj : Tool = Tool(tdef)
//ammo = 0
obj.AmmoTypeIndex mustEqual 0
obj.AmmoType mustEqual Ammo.shotgun_shell
//ammo -> 1
obj.NextAmmoType
obj.AmmoTypeIndex mustEqual 1
obj.AmmoType mustEqual Ammo.shotgun_shell_AP
//ammo -> 2 (0)
obj.NextAmmoType
obj.AmmoTypeIndex mustEqual 0
obj.AmmoType mustEqual Ammo.shotgun_shell
}
}
"Kit" should {
"define" in {
val sample = KitDefinition(Kits.medkit)
sample.ObjectId mustEqual medkit.ObjectId
sample.Tile.width mustEqual medkit.Tile.width
sample.Tile.height mustEqual medkit.Tile.height
}
"construct" in {
val obj : Kit = Kit(medkit)
obj.Definition.ObjectId mustEqual medkit.ObjectId
}
}
"ConstructionItem" should {
val advanced_ace_tr = ConstructionItemDefinition(39)
advanced_ace_tr.Modes += DeployedItem.tank_traps
advanced_ace_tr.Modes += DeployedItem.portable_manned_turret_tr
advanced_ace_tr.Modes += DeployedItem.deployable_shield_generator
advanced_ace_tr.Tile = InventoryTile.Tile63
"define" in {
val sample = ConstructionItemDefinition(Unit.advanced_ace)
sample.Modes += DeployedItem.tank_traps
sample.Modes += DeployedItem.portable_manned_turret_tr
sample.Modes += DeployedItem.deployable_shield_generator
sample.Tile = InventoryTile.Tile63
sample.Modes.head mustEqual DeployedItem.tank_traps
sample.Modes(1) mustEqual DeployedItem.portable_manned_turret_tr
sample.Modes(2) mustEqual DeployedItem.deployable_shield_generator
sample.Tile.width mustEqual InventoryTile.Tile63.width
sample.Tile.height mustEqual InventoryTile.Tile63.height
}
"construct" in {
val obj : ConstructionItem = ConstructionItem(advanced_ace_tr)
obj.Definition.ObjectId mustEqual advanced_ace_tr.ObjectId
}
"fire mode" in {
//explanation: router_telepad has one fire mode and that fire mode is our only option
val router_telepad : ConstructionItemDefinition = ConstructionItemDefinition(Unit.router_telepad)
router_telepad.Modes += DeployedItem.router_telepad_deployable
val obj : ConstructionItem = ConstructionItem(router_telepad)
//fmode = 0
obj.FireModeIndex mustEqual 0
obj.FireMode mustEqual DeployedItem.router_telepad_deployable
//fmode -> 1 (0)
obj.FireModeIndex = 1
obj.FireModeIndex mustEqual 0
obj.FireMode mustEqual DeployedItem.router_telepad_deployable
}
"multiple fire modes" in {
//explanation: advanced_ace_tr has three fire modes; adjusting the FireMode changes between them
val obj : ConstructionItem = ConstructionItem(advanced_ace_tr)
//fmode = 0
obj.FireModeIndex mustEqual 0
obj.FireMode mustEqual DeployedItem.tank_traps
//fmode -> 1
obj.NextFireMode
obj.FireModeIndex mustEqual 1
obj.FireMode mustEqual DeployedItem.portable_manned_turret_tr
//fmode -> 2
obj.NextFireMode
obj.FireModeIndex mustEqual 2
obj.FireMode mustEqual DeployedItem.deployable_shield_generator
//fmode -> 0
obj.NextFireMode
obj.FireModeIndex mustEqual 0
obj.FireMode mustEqual DeployedItem.tank_traps
}
}
"SimpleItem" should {
"define" in {
val sample = SimpleItemDefinition(SItem.remote_electronics_kit)
sample.ObjectId mustEqual remote_electronics_kit.ObjectId
}
"construct" in {
val obj : SimpleItem = SimpleItem(remote_electronics_kit)
obj.Definition.ObjectId mustEqual remote_electronics_kit.ObjectId
}
}
}

View file

@ -0,0 +1,76 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.Implant
import net.psforever.objects.definition.{ImplantDefinition, Stance}
import net.psforever.types.{ExoSuitType, ImplantType}
import org.specs2.mutable._
class ImplantTest extends Specification {
val sample = new ImplantDefinition(8) //variant of sensor shield/silent run
sample.Initialization = 90000 //1:30
sample.ActivationCharge = 3
sample.DurationChargeBase = 1
sample.DurationChargeByExoSuit += ExoSuitType.Agile -> 2
sample.DurationChargeByExoSuit += ExoSuitType.Reinforced -> 2
sample.DurationChargeByExoSuit += ExoSuitType.Standard -> 1
sample.DurationChargeByStance += Stance.Running -> 1
"define" in {
sample.Initialization mustEqual 90000
sample.ActivationCharge mustEqual 3
sample.DurationChargeBase mustEqual 1
sample.DurationChargeByExoSuit(ExoSuitType.Agile) mustEqual 2
sample.DurationChargeByExoSuit(ExoSuitType.Reinforced) mustEqual 2
sample.DurationChargeByExoSuit(ExoSuitType.Standard) mustEqual 1
sample.DurationChargeByExoSuit(ExoSuitType.Infiltration) mustEqual 0 //default value
sample.DurationChargeByStance(Stance.Running) mustEqual 1
sample.DurationChargeByStance(Stance.Crouching) mustEqual 0 //default value
sample.Type mustEqual ImplantType.SilentRun
}
"construct" in {
val obj = new Implant(sample)
obj.Definition.Type mustEqual sample.Type
obj.Active mustEqual false
obj.Ready mustEqual false
obj.Timer mustEqual 0
}
"reset/init their timer" in {
val obj = new Implant(sample)
obj.Timer mustEqual 0
obj.Reset()
obj.Timer mustEqual 90000
}
"reset/init their readiness condition" in {
val obj = new Implant(sample)
obj.Ready mustEqual false
obj.Timer = 0
obj.Ready mustEqual true
obj.Reset()
obj.Ready mustEqual false
}
"not activate until they are ready" in {
val obj = new Implant(sample)
obj.Active = true
obj.Active mustEqual false
obj.Timer = 0
obj.Active = true
obj.Active mustEqual true
}
"not cost energy while not active" in {
val obj = new Implant(sample)
obj.Charge(ExoSuitType.Reinforced, Stance.Running) mustEqual 0
}
"cost energy while active" in {
val obj = new Implant(sample)
obj.Timer = 0
obj.Active = true
obj.Charge(ExoSuitType.Reinforced, Stance.Running) mustEqual 4
}
}

View file

@ -0,0 +1,349 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.{AmmoBox, SimpleItem}
import net.psforever.objects.definition.SimpleItemDefinition
import net.psforever.objects.inventory.{GridInventory, InventoryItem, InventoryTile}
import net.psforever.objects.GlobalDefinitions._
import net.psforever.packet.game.PlanetSideGUID
import org.specs2.mutable._
import scala.collection.mutable.ListBuffer
import scala.util.Success
class InventoryTest extends Specification {
val bullet9mmBox1 = AmmoBox(PlanetSideGUID(1), bullet_9mm)
val bullet9mmBox2 = AmmoBox(PlanetSideGUID(2), bullet_9mm)
"GridInventory" should {
"construct" in {
val obj : GridInventory = GridInventory()
obj.TotalCapacity mustEqual 1
obj.Capacity mustEqual 1
}
"resize" in {
val obj : GridInventory = GridInventory(9, 6)
obj.TotalCapacity mustEqual 54
obj.Capacity mustEqual 54
obj.Size mustEqual 0
}
"insert item" in {
val obj : GridInventory = GridInventory(9, 6)
obj.CheckCollisions(23, bullet9mmBox1) mustEqual Success(Nil)
obj += 2 -> bullet9mmBox1
obj.TotalCapacity mustEqual 54
obj.Capacity mustEqual 45
obj.Size mustEqual 1
obj.hasItem(PlanetSideGUID(1)) mustEqual Some(bullet9mmBox1)
obj.Clear()
obj.Size mustEqual 0
}
"check for collision with inventory border" in {
val obj : GridInventory = GridInventory(3, 3)
//safe
obj.CheckCollisionsAsList(0, 3, 3) mustEqual Success(Nil)
//right
obj.CheckCollisionsAsList(-1, 3, 3).isFailure mustEqual true
//left
obj.CheckCollisionsAsList(1, 3, 3).isFailure mustEqual true
//bottom
obj.CheckCollisionsAsList(3, 3, 3).isFailure mustEqual true
}
"check for item collision (right insert)" in {
val obj : GridInventory = GridInventory(9, 6)
obj += 0 -> bullet9mmBox1
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.width
val h = bullet9mmBox2.Tile.height
val list0 = obj.CheckCollisionsAsList(0, w, h)
list0 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list1 = obj.CheckCollisionsAsList(1, w, h)
list1 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list2 = obj.CheckCollisionsAsList(2, w, h)
list2 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list3 = obj.CheckCollisionsAsList(3, w, h)
list3 match {
case scala.util.Success(list) => list.isEmpty mustEqual true
case scala.util.Failure(_) => ko
}
obj.CheckCollisionsAsGrid(0, w, h) mustEqual list0
obj.CheckCollisionsAsGrid(1, w, h) mustEqual list1
obj.CheckCollisionsAsGrid(2, w, h) mustEqual list2
obj.CheckCollisionsAsGrid(3, w, h) mustEqual list3
obj.Clear()
ok
}
"check for item collision (left insert)" in {
val obj : GridInventory = GridInventory(9, 6)
obj += 3 -> bullet9mmBox1
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.width
val h = bullet9mmBox2.Tile.height
val list0 = obj.CheckCollisionsAsList(3, w, h)
list0 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list1 = obj.CheckCollisionsAsList(2, w, h)
list1 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list2 = obj.CheckCollisionsAsList(1, w, h)
list2 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list3 = obj.CheckCollisionsAsList(0, w, h)
list3 match {
case scala.util.Success(list) => list.isEmpty mustEqual true
case scala.util.Failure(_) => ko
}
obj.CheckCollisionsAsGrid(3, w, h) mustEqual list0
obj.CheckCollisionsAsGrid(2, w, h) mustEqual list1
obj.CheckCollisionsAsGrid(1, w, h) mustEqual list2
obj.CheckCollisionsAsGrid(0, w, h) mustEqual list3
obj.Clear()
ok
}
"check for item collision (below insert)" in {
val obj : GridInventory = GridInventory(9, 6)
obj += 0 -> bullet9mmBox1
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.width
val h = bullet9mmBox2.Tile.height
val list0 = obj.CheckCollisionsAsList(0, w, h)
list0 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list1 = obj.CheckCollisionsAsList(9, w, h)
list1 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list2 = obj.CheckCollisionsAsList(18, w, h)
list2 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list3 = obj.CheckCollisionsAsList(27, w, h)
list3 match {
case scala.util.Success(list) => list.isEmpty mustEqual true
case scala.util.Failure(_) => ko
}
obj.CheckCollisionsAsGrid(0, w, h) mustEqual list0
obj.CheckCollisionsAsGrid(9, w, h) mustEqual list1
obj.CheckCollisionsAsGrid(18, w, h) mustEqual list2
obj.CheckCollisionsAsGrid(27, w, h) mustEqual list3
obj.Clear()
ok
}
"check for item collision (above insert)" in {
val obj : GridInventory = GridInventory(9, 6)
obj += 27 -> bullet9mmBox1
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.width
val h = bullet9mmBox2.Tile.height
val list0 = obj.CheckCollisionsAsList(27, w, h)
list0 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list1 = obj.CheckCollisionsAsList(18, w, h)
list1 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list2 = obj.CheckCollisionsAsList(9, w, h)
list2 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list3 = obj.CheckCollisionsAsList(0, w, h)
list3 match {
case scala.util.Success(list) => list.isEmpty mustEqual true
case scala.util.Failure(_) => ko
}
obj.CheckCollisionsAsGrid(27, w, h) mustEqual list0
obj.CheckCollisionsAsGrid(18, w, h) mustEqual list1
obj.CheckCollisionsAsGrid(9, w, h) mustEqual list2
obj.CheckCollisionsAsGrid(0, w, h) mustEqual list3
obj.Clear()
ok
}
"check for item collision (diagonal insert)" in {
/*
Number indicates upper-left corner of attempted 3x3 insertion by list#
0 - - - - - 2 - - - - -
- 1 - - - 3 - - - - - -
- - - - - - - - - - - -
- - - X X X - - - - - -
- - - X X X - - - - - -
- 5 - X X 7 - - - - - -
4 - - - - - 6 - - - - -
- - - - - - - - - - - -
- - - - - - - - - - - -
*/
val obj : GridInventory = GridInventory(12, 9)
obj += 39 -> bullet9mmBox1
obj.Capacity mustEqual 99 //108 - 9
val w = bullet9mmBox2.Tile.width
val h = bullet9mmBox2.Tile.height
val list0 = obj.CheckCollisionsAsList(0, w, h)
list0 match {
case scala.util.Success(list) => list.isEmpty mustEqual true
case scala.util.Failure(_) => ko
}
val list1 = obj.CheckCollisionsAsList(13, w, h)
list1 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list2 = obj.CheckCollisionsAsList(6, w, h)
list2 match {
case scala.util.Success(list) =>list.isEmpty mustEqual true
case scala.util.Failure(_) => ko
}
val list3 = obj.CheckCollisionsAsList(17, w, h)
list3 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list4 = obj.CheckCollisionsAsList(72, w, h)
list4 match {
case scala.util.Success(list) => list.isEmpty mustEqual true
case scala.util.Failure(_) => ko
}
val list5 = obj.CheckCollisionsAsList(61, w, h)
list5 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
val list6 = obj.CheckCollisionsAsList(78, w, h)
list6 match {
case scala.util.Success(list) => list.isEmpty mustEqual true
case scala.util.Failure(_) => ko
}
val list7 = obj.CheckCollisionsAsList(65, w, h)
list7 match {
case scala.util.Success(list) => list.length mustEqual 1
case scala.util.Failure(_) => ko
}
obj.CheckCollisionsAsGrid(0, w, h) mustEqual list0
obj.CheckCollisionsAsGrid(13, w, h) mustEqual list1
obj.CheckCollisionsAsGrid(6, w, h) mustEqual list2
obj.CheckCollisionsAsGrid(17, w, h) mustEqual list3
obj.CheckCollisionsAsGrid(72, w, h) mustEqual list4
obj.CheckCollisionsAsGrid(61, w, h) mustEqual list5
obj.CheckCollisionsAsGrid(78, w, h) mustEqual list6
obj.CheckCollisionsAsGrid(65, w, h) mustEqual list7
obj.Clear()
ok
}
"block insertion if item collision" in {
val obj : GridInventory = GridInventory(9, 6)
obj += 0 -> bullet9mmBox1
obj.Capacity mustEqual 45
obj.hasItem(PlanetSideGUID(1)) mustEqual Some(bullet9mmBox1)
obj += 2 -> bullet9mmBox2
obj.hasItem(PlanetSideGUID(2)) mustEqual None
obj.Clear()
ok
}
"remove item" in {
val obj : GridInventory = GridInventory(9, 6)
obj += 0 -> bullet9mmBox1
obj.hasItem(PlanetSideGUID(1)) mustEqual Some(bullet9mmBox1)
obj -= PlanetSideGUID(1)
obj.hasItem(PlanetSideGUID(1)) mustEqual None
obj.Clear()
ok
}
"unblock insertion on item removal" in {
val obj : GridInventory = GridInventory(9, 6)
obj.CheckCollisions(23, bullet9mmBox1) mustEqual Success(Nil)
obj += 23 -> bullet9mmBox1
obj.hasItem(PlanetSideGUID(1)) mustEqual Some(bullet9mmBox1)
obj.CheckCollisions(23, bullet9mmBox1) mustEqual Success(1 :: Nil)
obj -= PlanetSideGUID(1)
obj.hasItem(PlanetSideGUID(1)) mustEqual None
obj.CheckCollisions(23, bullet9mmBox1) mustEqual Success(Nil)
obj.Clear()
ok
}
"attempt to fit an item" in {
val sampleDef22 = new SimpleItemDefinition(149)
sampleDef22.Tile = InventoryTile.Tile22
val sampleDef33 = new SimpleItemDefinition(149)
sampleDef33.Tile = InventoryTile.Tile33
val sampleDef63 = new SimpleItemDefinition(149)
sampleDef63.Tile = InventoryTile.Tile63
val obj : GridInventory = GridInventory(9, 9)
obj += 0 -> SimpleItem(PlanetSideGUID(0), sampleDef22)
obj += 20 -> SimpleItem(PlanetSideGUID(1), sampleDef63)
obj += 56 -> SimpleItem(PlanetSideGUID(2), sampleDef33)
obj.Fit(InventoryTile.Tile33) match {
case Some(x) =>
x mustEqual 50
case None =>
ko
}
ok
}
"attempt to fit all the items" in {
val sampleDef1 = new SimpleItemDefinition(149)
sampleDef1.Tile = InventoryTile.Tile22
val sampleDef2 = new SimpleItemDefinition(149)
sampleDef2.Tile = InventoryTile.Tile33
val sampleDef3 = new SimpleItemDefinition(149)
sampleDef3.Tile = InventoryTile.Tile42
val sampleDef4 = new SimpleItemDefinition(149)
sampleDef4.Tile = InventoryTile.Tile63
val list : ListBuffer[InventoryItem] = ListBuffer()
list += new InventoryItem(SimpleItem(PlanetSideGUID(0), sampleDef2), -1)
list += new InventoryItem(SimpleItem(PlanetSideGUID(1), sampleDef3), -1)
list += new InventoryItem(SimpleItem(PlanetSideGUID(2), sampleDef1), -1)
list += new InventoryItem(SimpleItem(PlanetSideGUID(3), sampleDef4), -1)
list += new InventoryItem(SimpleItem(PlanetSideGUID(4), sampleDef1), -1)
list += new InventoryItem(SimpleItem(PlanetSideGUID(5), sampleDef4), -1)
list += new InventoryItem(SimpleItem(PlanetSideGUID(6), sampleDef2), -1)
list += new InventoryItem(SimpleItem(PlanetSideGUID(7), sampleDef3), -1)
val obj : GridInventory = GridInventory(9, 9)
val (elements, out) = GridInventory.recoverInventory(list.toList, obj)
elements.length mustEqual 6
out.length mustEqual 2
elements.foreach(item => {
obj.Insert(item.start, item.obj) mustEqual true
})
out.head.Definition.Tile mustEqual InventoryTile.Tile22 //did not fit
out(1).Definition.Tile mustEqual InventoryTile.Tile22 //did not fit
ok
}
}
}

View file

@ -0,0 +1,83 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{ActorSystem, Props}
import akka.testkit.{ImplicitSender, TestKit, TestProbe}
import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.guid.NumberPoolHub
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
import net.psforever.objects.guid.actor.{NumberPoolAccessorActor, NumberPoolActor, Register}
import net.psforever.objects.guid.pool.ExclusivePool
import net.psforever.objects.guid.selector.RandomSelector
import net.psforever.objects.guid.source.LimitedNumberSource
import org.specs2.specification.Scope
import scala.concurrent.duration.Duration
import scala.util.Success
abstract class ActorTest(sys : ActorSystem) extends TestKit(sys) with Scope with ImplicitSender with WordSpecLike with Matchers with BeforeAndAfterAll {
override def afterAll {
TestKit.shutdownActorSystem(system)
}
}
class NumberPoolActorTest extends ActorTest(ActorSystem("test")) {
"NumberPoolActor" should {
"GetAnyNumber" in {
val pool = new ExclusivePool((25 to 50).toList)
pool.Selector = new RandomSelector
val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor1")
poolActor ! NumberPoolActor.GetAnyNumber()
val msg = receiveOne(Duration.create(100, "ms"))
assert(msg.isInstanceOf[NumberPoolActor.GiveNumber])
}
}
}
class NumberPoolActorTest1 extends ActorTest(ActorSystem("test")) {
"NumberPoolActor" should {
"GetSpecificNumber" in {
val pool = new ExclusivePool((25 to 50).toList)
pool.Selector = new RandomSelector
val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor2")
poolActor ! NumberPoolActor.GetSpecificNumber(37)
expectMsg(NumberPoolActor.GiveNumber(37, None))
}
}
}
class NumberPoolActorTest2 extends ActorTest(ActorSystem("test")) {
"NumberPoolActor" should {
"NoNumber" in {
val pool = new ExclusivePool((25 to 25).toList) //pool only has one number - 25
pool.Selector = new RandomSelector
val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor3")
poolActor ! NumberPoolActor.GetAnyNumber()
expectMsg(NumberPoolActor.GiveNumber(25, None))
poolActor ! NumberPoolActor.GetAnyNumber()
val msg = receiveOne(Duration.create(100, "ms"))
assert(msg.isInstanceOf[NumberPoolActor.NoNumber])
}
}
}
class NumberPoolActorTest3 extends ActorTest(ActorSystem("test")) {
"NumberPoolAccessorActor" should {
class TestEntity extends IdentifiableEntity
"register" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
val pool = hub.AddPool("test", (25 to 50).toList)
pool.Selector = new RandomSelector
val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor")
val poolAccessor = system.actorOf(Props(classOf[NumberPoolAccessorActor], hub, pool, poolActor), name = "accessor")
val obj : TestEntity = new TestEntity
val probe = new TestProbe(system)
poolAccessor ! Register(obj, probe.ref)
probe.expectMsg(Success(obj))
assert({obj.GUID; true}) //NoGUIDException if failure
}
}
}

View file

@ -0,0 +1,285 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.selector.RandomSelector
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.packet.game.PlanetSideGUID
import org.specs2.mutable.Specification
import scala.util.Success
class NumberPoolHubTest extends Specification {
val numberList = 0 :: 1 :: 2 :: 3 :: 5 :: 8 :: 13 :: 21 :: Nil
val numberList1 = 0 :: 1 :: 2 :: 3 :: 5 :: Nil
val numberList2 = 8 :: 13 :: 21 :: 34 :: Nil
val numberSet1 = numberList1.toSet
val numberSet2 = numberList2.toSet
class EntityTestClass extends IdentifiableEntity
"NumberPoolHub" should {
"construct" in {
new NumberPoolHub(new LimitedNumberSource(51))
ok
}
"get a pool" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.GetPool("generic").isDefined mustEqual true //default pool
}
"add a pool" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.Numbers.isEmpty mustEqual true
obj.AddPool("fibonacci", numberList)
obj.Numbers.toSet.equals(numberList.toSet) mustEqual true
val pool = obj.GetPool("fibonacci")
pool.isDefined mustEqual true
pool.get.Numbers.equals(numberList)
}
"enumerate the content of all pools" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.AddPool("fibonacci1", numberList1)
obj.AddPool("fibonacci2", numberList2)
numberSet1.intersect(obj.Numbers.toSet) mustEqual numberSet1
numberSet2.intersect(obj.Numbers.toSet) mustEqual numberSet2
obj.Numbers.toSet.diff(numberSet1) mustEqual numberSet2
}
"remove a pool" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.Numbers.isEmpty mustEqual true
obj.AddPool("fibonacci", numberList)
obj.Numbers.toSet.equals(numberList.toSet) mustEqual true
obj.RemovePool("fibonacci").toSet.equals(numberList.toSet) mustEqual true
obj.Numbers.isEmpty mustEqual true
obj.GetPool("fibonacci") mustEqual None
}
"block removing the default 'generic' pool" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.RemovePool("generic") must throwA[IllegalArgumentException]
}
"block adding pools that use already-included numbers" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.AddPool("fibonacci1", numberList)
val numberList4 = 3 :: 7 :: 21 :: 34 :: 45 :: Nil
obj.AddPool("fibonacci2", numberList4) must throwA[IllegalArgumentException]
}
"enumerate only the content of all current pools" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.AddPool("fibonacci1", numberList1)
obj.AddPool("fibonacci2", numberList2)
numberSet1.intersect(obj.Numbers.toSet) mustEqual numberSet1
numberSet2.intersect(obj.Numbers.toSet) mustEqual numberSet2
obj.RemovePool("fibonacci1")
numberSet1.intersect(obj.Numbers.toSet) mustEqual Set() //no intersect
numberSet2.intersect(obj.Numbers.toSet) mustEqual numberSet2
}
"register an object to a pool" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass()
obj.GUID must throwA[Exception]
hub.register(obj, "fibonacci") match {
case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number)
case _ =>
ko
}
}
"lookup a registered object" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass()
hub.register(obj, "fibonacci") match {
case Success(number) =>
val objFromNumber = hub(number)
objFromNumber mustEqual Some(obj)
case _ =>
ko
}
}
"lookup the pool of a(n unassigned) number" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci1", numberList1)
hub.AddPool("fibonacci2", numberList2)
hub.WhichPool(13) mustEqual Some("fibonacci2")
}
"lookup the pool of a registered object" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList1)
val obj = new EntityTestClass()
hub.register(obj, "fibonacci")
hub.WhichPool(obj) mustEqual Some("fibonacci")
}
"register an object to a specific, unused number; it is assigned to pool 'generic'" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList1)
val obj = new EntityTestClass()
obj.GUID must throwA[Exception]
hub.register(obj, 44) match {
case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number)
hub.WhichPool(obj) mustEqual Some("generic")
case _ =>
ko
}
}
"register an object to a specific, pooled number" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass()
obj.GUID must throwA[Exception]
hub.register(obj, 13) match {
case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number)
hub.WhichPool(obj) mustEqual Some("fibonacci")
case _ =>
ko
}
}
"register an object without extra specifications; it is assigned to pool 'generic'" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
val obj = new EntityTestClass()
hub.register(obj)
hub.WhichPool(obj) mustEqual Some("generic")
}
"unregister an object" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass()
hub.register(obj, "fibonacci")
hub.WhichPool(obj) mustEqual Some("fibonacci")
try { obj.GUID } catch { case _ : Exception => ko } //passes
hub.unregister(obj)
hub.WhichPool(obj) mustEqual None
obj.GUID must throwA[Exception] //fails
}
"not register an object to a different pool" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci1", numberList1)
hub.AddPool("fibonacci2", numberList2)
val obj = new EntityTestClass()
hub.register(obj, "fibonacci1")
hub.register(obj, "fibonacci2")
hub.WhichPool(obj).contains("fibonacci1") mustEqual true
}
"fail to unregister an object that is not registered to this hub" in {
val hub1 = new NumberPoolHub(new LimitedNumberSource(51))
val hub2 = new NumberPoolHub(new LimitedNumberSource(51))
hub1.AddPool("fibonacci", numberList)
hub2.AddPool("fibonacci", numberList)
val obj = new EntityTestClass()
hub1.register(obj, "fibonacci")
hub2.unregister(obj) must throwA[Exception]
}
"pre-register a specific, unused number" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.register(13) match {
case Success(_) =>
ok
case _ =>
ko
}
}
"pre-register a specific, pooled number" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList)
hub.register(13) match {
case Success(key) =>
key.GUID mustEqual 13
case _ =>
ko
}
}
"pre-register a number from a known pool" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList).Selector = new RandomSelector
hub.register("fibonacci") match {
case Success(key) =>
numberList.contains(key.GUID) mustEqual true
case _ =>
ko
}
}
"unregister a number" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList).Selector = new RandomSelector //leave this tagged on
val obj = new EntityTestClass()
hub.register(13) match {
case Success(key) =>
key.Object = obj
case _ =>
ko
}
hub.WhichPool(obj) mustEqual Some("fibonacci")
hub.unregister(13) match {
case Success(thing) =>
thing mustEqual Some(obj)
thing.get.GUID must throwA[Exception]
case _ =>
ko
}
}
"not affect the hidden restricted pool by adding a new pool" in {
val src = new LimitedNumberSource(51)
src.Restrict(4)
src.Restrict(8) //in fibonacci
src.Restrict(10)
src.Restrict(12)
val hub = new NumberPoolHub(src)
hub.AddPool("fibonacci", numberList) must throwA[IllegalArgumentException]
}
"not register an object to a number belonging to the restricted pool" in {
val src = new LimitedNumberSource(51)
src.Restrict(4)
val hub = new NumberPoolHub(src)
val obj = new EntityTestClass()
hub.register(obj, 4).isFailure mustEqual true
}
"not register an object to the restricted pool directly" in {
val src = new LimitedNumberSource(51)
// src.Restrict(4)
val hub = new NumberPoolHub(src)
val obj = new EntityTestClass()
hub.register(obj, "").isFailure mustEqual true //the empty string represents the restricted pool
}
"not register a number belonging to the restricted pool" in {
val src = new LimitedNumberSource(51)
src.Restrict(4)
val hub = new NumberPoolHub(src)
hub.register(4).isFailure mustEqual true
}
"not unregister a number belonging to the restricted pool" in {
val src = new LimitedNumberSource(51)
src.Restrict(4)
val hub = new NumberPoolHub(src)
hub.unregister(4).isFailure mustEqual true
}
}
}

View file

@ -0,0 +1,194 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.guid.pool.{ExclusivePool, GenericPool, SimplePool}
import net.psforever.objects.guid.selector.SpecificSelector
import org.specs2.mutable.Specification
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.util.Success
class NumberPoolTest extends Specification {
"SimplePool" should {
"construct" in {
new SimplePool(0 :: 1 :: 2 :: Nil)
ok
}
"get a number" in {
val obj = new SimplePool((0 to 10).toList)
obj.Get() match {
case Success(number) =>
(-1 < number && number < 11) mustEqual true
case _ =>
ko
}
}
"return a number" in {
//returning a number for a SimplePool is actually just a way of checking that the number is in the "pool" at all
val obj = new SimplePool((0 to 10).toList)
obj.Get() match {
case Success(number) =>
obj.Return(number) mustEqual true
obj.Return(11) mustEqual false
obj.Return(number) mustEqual true
case _ =>
ko
}
}
"numbers remain available" in {
val obj = new SimplePool((0 to 10).toList)
obj.Selector = new SpecificSelector
obj.Selector.asInstanceOf[SpecificSelector].SelectionIndex = 8
obj.Get() mustEqual Success(8)
obj.Get() mustEqual Success(8) //compare to how SpecificSelector works otherwise - it would be an invalid return
}
}
"ExclusivePool" should {
"construct" in {
new ExclusivePool(0 :: 1 :: 2 :: Nil)
ok
}
"get a number" in {
val obj = new ExclusivePool((0 to 10).toList)
obj.Get() match {
case Success(number) =>
(-1 < number && number < 11) mustEqual true
case _ =>
ko
}
}
"get all the numbers" in {
val range = 0 to 10
val obj = new ExclusivePool((0 to 10).toList)
range.foreach(_ => {
obj.Get() match {
case Success(number) =>
(-1 < number && number < 11) mustEqual true
case _ =>
ko
}
})
ok
}
"return a number" in {
val obj = new ExclusivePool((0 to 10).toList)
obj.Get() match {
case Success(number) =>
try { obj.Return(number) mustEqual true } catch { case _ : Exception => ko }
case _ =>
ko
}
}
"return all the numbers" in {
val range = 0 to 10
val obj = new ExclusivePool((0 to 10).toList)
val list : ListBuffer[Int] = ListBuffer[Int]()
range.foreach(_ => {
obj.Get() match {
case Success(number) =>
list += number
case _ =>
}
})
list.foreach(number => {
try { obj.Return(number) mustEqual true } catch { case _ : Exception => ko }
})
ok
}
}
"GenericPool" should {
"construct" in {
new GenericPool(mutable.LongMap[String](), 11)
ok
}
"get a provided number" in {
val map = mutable.LongMap[String]()
val obj = new GenericPool(map, 11)
obj.Numbers.isEmpty mustEqual true
obj.Selector.asInstanceOf[SpecificSelector].SelectionIndex = 5
obj.Get() match {
case Success(number) =>
number mustEqual 5
map.contains(5) mustEqual true
map(5) mustEqual "generic"
obj.Numbers.contains(5) mustEqual true
case _ =>
ko
}
}
"return a number" in {
val map = mutable.LongMap[String]()
val obj = new GenericPool(map, 11)
obj.Selector.asInstanceOf[SpecificSelector].SelectionIndex = 5
obj.Get()
map.get(5) mustEqual Some("generic")
obj.Numbers.contains(5) mustEqual true
obj.Return(5) mustEqual true
map.get(5) mustEqual None
obj.Numbers.isEmpty mustEqual true
}
"block on numbers that are already defined" in {
val map = mutable.LongMap[String]()
map += 5L -> "test" //5 is defined
val obj = new GenericPool(map, 11)
obj.Numbers.isEmpty mustEqual true
obj.Selector.asInstanceOf[SpecificSelector].SelectionIndex = 5 //5 is requested
obj.Get() match {
case Success(_) =>
ko
case _ =>
obj.Numbers.isEmpty mustEqual true
}
}
"get a free number on own if none provided" in {
val map = mutable.LongMap[String]()
val obj = new GenericPool(map, 11)
obj.Get() match {
case Success(number) =>
number mustEqual 5
case _ =>
ko
}
}
"get a free number that is not already defined" in {
val map = mutable.LongMap[String]()
map += 5L -> "test" //5 is defined; think, -1 :: 5 :: 11
val obj = new GenericPool(map, 11)
obj.Get() match {
case Success(number) =>
number mustEqual 2 // think, -1 :: 2 :: 5 :: 11
case _ => ko
}
}
"get a free number that represents half of the largest delta" in {
val map = mutable.LongMap[String]()
map += 5L -> "test" //5 is defined; think, -1 :: 5 :: 11
map += 4L -> "test" //4 is defined; think, -1 :: 4 :: 5 :: 11
val obj = new GenericPool(map, 11)
obj.Get() match {
case Success(number) =>
number mustEqual 8 // think, -1 :: 4 :: 5 :: 8 :: 11
case _ =>
ko
}
}
}
}

View file

@ -0,0 +1,326 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.guid.selector.{RandomSequenceSelector, _}
import org.specs2.mutable.Specification
class NumberSelectorTest extends Specification {
def randArrayGen(n : Int = 26) : Array[Int] = {
val obj = Array.ofDim[Int](n)
(0 to 25).foreach(x => { obj(x) = x } )
obj
}
"RandomSequenceSelector" should {
"construct" in {
new RandomSequenceSelector
ok
}
"get a number" in {
val obj = new RandomSequenceSelector
obj.Get(randArrayGen()) mustNotEqual -1
}
"return a number" in {
val obj = new RandomSequenceSelector
val ary = randArrayGen()
val number = obj.Get(ary)
number mustNotEqual -1
ary.head mustEqual -1 //regardless of which number we actually got, the head of the array is now -1
obj.Return(number, ary)
ary.head mustEqual number //the returned number is at the head of the array
}
"get all numbers" in {
val n = 26
val obj = new RandomSequenceSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 } )
ok
}
"return all numbers" in {
val n = 26
val obj = new RandomSequenceSelector
val ary1 = randArrayGen(n)
val ary2 = randArrayGen(n)
(0 until n).foreach(index => { ary2(index) = obj.Get(ary1) } ) //move numbers from ary1 to ary2
ary2.toSet.diff(ary1.toSet).size mustEqual n //no numbers between ary2 and ary1 match
(0 until n).foreach(index => { obj.Return(ary2(index), ary1) mustEqual true } ) //return numbers from ary2 to ary1
ary2.toSet.diff(ary1.toSet).size mustEqual 0 //no difference in the content between ary2 and ary1
}
"gets invalid index when exhausted" in {
val n = 26
val obj = new RandomSequenceSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 } )
obj.Get(ary) mustEqual -1
}
"format an array" in {
val ary = Array[Int](1, -1, 5, 3, -1, 2)
(new RandomSequenceSelector).Format(ary)
ary mustEqual Array[Int](-1, -1, 1, 5, 3, 2)
}
}
"RandomSelector" should {
"construct" in {
new RandomSelector
ok
}
"get a number" in {
val obj = new RandomSelector
obj.Get(randArrayGen()) mustNotEqual -1
}
"return a number" in {
val obj = new RandomSelector
val ary = randArrayGen()
val number = obj.Get(ary)
number mustNotEqual -1
ary.head mustEqual -1 //regardless of which number we actually got, the head of the array is now -1
obj.Return(number, ary)
ary.head mustEqual number //the returned number is at the head of the array
}
"get all numbers" in {
val n = 26
val obj = new RandomSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 } )
ok
}
"return all numbers" in {
val n = 26
val obj = new RandomSelector
val ary1 = randArrayGen(n)
val ary2 = randArrayGen(n)
(0 until n).foreach(index => { ary2(index) = obj.Get(ary1) } ) //move numbers from ary1 to ary2
ary2.toSet.diff(ary1.toSet).size mustEqual n //no numbers between ary2 and ary1 match
(0 until n).foreach(index => { obj.Return(ary2(index), ary1) mustEqual true } ) //return numbers from ary2 to ary1
ary2.toSet.diff(ary1.toSet).size mustEqual 0 //no difference in the content between ary2 and ary1
}
"gets invalid index when exhausted" in {
val n = 26
val obj = new RandomSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 } )
obj.Get(ary) mustEqual -1
}
"format an array" in {
val ary = Array[Int](1, -1, 5, 3, -1, 2)
(new RandomSelector).Format(ary)
ary mustEqual Array[Int](-1, -1, 1, 5, 3, 2)
}
}
"StrictInOrderSelector" should {
"construct" in {
new StrictInOrderSelector
ok
}
"get a number" in {
val obj = new StrictInOrderSelector
obj.Get(randArrayGen()) mustNotEqual -1
}
"return a number" in {
val obj = new StrictInOrderSelector
val ary = randArrayGen()
val number = obj.Get(ary)
number mustNotEqual -1
ary.head mustEqual -1 //regardless of which number we actually got, the head of the array is now -1
obj.Return(number, ary)
ary.head mustEqual number //the returned number is at the head of the array
}
"get all numbers" in {
val n = 26
val obj = new StrictInOrderSelector
val ary = randArrayGen()
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 } )
ok
}
"return all numbers" in {
val n = 26
val obj = new StrictInOrderSelector
val ary1 = randArrayGen(n)
val ary2 = randArrayGen(n)
(0 until n).foreach(index => { ary2(index) = obj.Get(ary1) } ) //move numbers from ary1 to ary2
ary2.toSet.diff(ary1.toSet).size mustEqual n //no numbers between ary2 and ary1 match
(0 until n).foreach(index => { obj.Return(ary2(index), ary1) mustEqual true } ) //return numbers from ary2 to ary1
ary2.toSet.diff(ary1.toSet).size mustEqual 0 //no difference in the content between ary2 and ary1
}
"gets invalid index when exhausted" in {
val n = 26
val obj = new StrictInOrderSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 } )
obj.Get(ary) mustEqual -1
}
"wait until number is available" in {
val n = 26
val obj = new StrictInOrderSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 } )
obj.Get(ary) mustEqual -1
obj.Return(1, ary) //return a number that isn't the one StrictOrder is waiting on
obj.Get(ary) mustEqual -1
obj.Return(0, ary) //return the number StrictOrder wants
obj.Get(ary) mustEqual 0
obj.Get(ary) mustEqual 1
}
"format an array" in {
val ary = Array[Int](1, -1, 5, 3, -1, 2)
(new StrictInOrderSelector).Format(ary)
ary mustEqual Array[Int](-1, 1, 2, 3, -1, 5)
}
}
"OpportunisticSelector" should {
"construct" in {
new OpportunisticSelector
ok
}
"get a number" in {
val obj = new OpportunisticSelector
obj.Get(randArrayGen()) mustNotEqual -1
}
"return a number" in {
val obj = new OpportunisticSelector
val ary = randArrayGen()
val number = obj.Get(ary)
number mustNotEqual -1
ary.head mustEqual -1 //regardless of which number we actually got, the head of the array is now -1
obj.Return(number, ary)
ary.head mustEqual number //the returned number is at the head of the array
}
"get all numbers" in {
val obj = new OpportunisticSelector
val ary = randArrayGen()
(0 to 25).foreach(_ => { obj.Get(ary) mustNotEqual -1 } )
ok
}
"return all numbers" in {
val n = 26
val obj = new OpportunisticSelector
val ary1 = randArrayGen(n)
val ary2 = randArrayGen(n)
(0 until n).foreach(index => { ary2(index) = obj.Get(ary1) } ) //move numbers from ary1 to ary2
ary2.toSet.diff(ary1.toSet).size mustEqual n //no numbers between ary2 and ary1 match
(0 until n).foreach(index => { obj.Return(ary2(index), ary1) mustEqual true } ) //return numbers from ary2 to ary1
ary2.toSet.diff(ary1.toSet).size mustEqual 0 //no difference in the content between ary2 and ary1
}
"gets invalid index when exhausted" in {
val n = 26
val obj = new OpportunisticSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 } )
obj.Get(ary) mustEqual -1
}
"format an array" in {
val ary = Array[Int](1, -1, 5, 3, -1, 2)
(new OpportunisticSelector).Format(ary)
ary mustEqual Array[Int](-1, -1, 1, 5, 3, 2)
}
}
"SpecificSelector" should {
"construct" in {
new SpecificSelector
ok
}
"get a number" in {
val obj = new SpecificSelector
val ary = randArrayGen()
obj.SelectionIndex = 5
obj.Get(ary) mustEqual 5
obj.Get(ary) mustEqual -1 //now that 5 has been selected, the selector will only get a -1 from that position
}
"return a number" in {
val obj = new SpecificSelector
val ary = randArrayGen()
obj.SelectionIndex = 5
val number = obj.Get(ary)
number mustEqual 5
obj.Get(ary) mustEqual -1
obj.Return(number, ary)
obj.Get(ary) mustEqual number //the returned number is at the head of the array
}
"return a number (2)" in {
val obj = new SpecificSelector
val ary = randArrayGen()
obj.SelectionIndex = 5
val number = obj.Get(ary)
number mustEqual 5
obj.Get(ary) mustEqual -1
ary(number) mustEqual -1
obj.SelectionIndex = 10 //even if we move the selection index, the number will return to its last position
obj.Return(number, ary)
ary(number) mustEqual number //the returned number at the original index
obj.Get(ary) mustEqual 10 //of course, with the selection index changed, we will not get the same position next time
}
"get all numbers" in {
val n = 26
val obj = new SpecificSelector
val ary = randArrayGen(n)
(0 until n).foreach(i => {
obj.SelectionIndex = i
obj.Get(ary) mustEqual i
})
ok
}
"return all numbers" in {
val n = 26
val obj = new SpecificSelector
val ary1 = randArrayGen(n)
val ary2 = randArrayGen(n)
(0 until n).foreach(index => {
obj.SelectionIndex = index
ary2(index) = obj.Get(ary1)
}) //move numbers from ary1 to ary2
ary2.toSet.diff(ary1.toSet).size mustEqual n //no numbers between ary2 and ary1 match
(0 until n).foreach(index => { obj.Return(ary2(index), ary1) mustEqual true } ) //return numbers from ary2 to ary1
ary2.toSet.diff(ary1.toSet).size mustEqual 0 //no difference in the content between ary2 and ary1
}
"gets invalid index when exhausted" in {
val obj = new SpecificSelector
val ary = randArrayGen()
obj.SelectionIndex = 5
obj.Get(ary) mustEqual 5
obj.Get(ary) mustEqual -1 //yes, it really is that simple
}
"format an array" in {
val ary = Array[Int](1, -1, 5, 3, -1, 2)
(new SpecificSelector).Format(ary)
ary mustEqual Array[Int](-1, 1, 2, 3, -1, 5)
}
}
}

View file

@ -0,0 +1,359 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.guid.key.{LoanedKey, SecureKey}
import net.psforever.objects.guid.AvailabilityPolicy
import org.specs2.mutable.Specification
class NumberSourceTest extends Specification {
import net.psforever.objects.entity.IdentifiableEntity
private class TestClass extends IdentifiableEntity
"MaxNumberSource" should {
import net.psforever.objects.guid.source.MaxNumberSource
"construct" in {
val obj = MaxNumberSource()
obj.Size mustEqual Int.MaxValue
obj.CountAvailable mustEqual Int.MaxValue
obj.CountUsed mustEqual 0
}
"get a number" in {
val obj = MaxNumberSource()
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object mustEqual None
obj.Size mustEqual Int.MaxValue
obj.CountAvailable mustEqual Int.MaxValue - 1
obj.CountUsed mustEqual 1
}
"assign the number" in {
val obj = MaxNumberSource()
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.Object = new TestClass()
ok
}
"return a number (unused)" in {
val obj = MaxNumberSource()
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
obj.CountUsed mustEqual 1
val ret = obj.Return(result.get)
ret mustEqual None
obj.CountUsed mustEqual 0
}
"return a number (assigned)" in {
val obj = MaxNumberSource()
val test = new TestClass()
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Object = test
obj.CountUsed mustEqual 1
val ret = obj.Return(result.get)
ret mustEqual Some(test)
obj.CountUsed mustEqual 0
}
"restrict a number (unassigned)" in {
val obj = MaxNumberSource()
val result : Option[LoanedKey] = obj.Restrict(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object mustEqual None
}
"restrict a number (assigned + multiple assignments)" in {
val obj = MaxNumberSource()
val test1 = new TestClass()
val test2 = new TestClass()
val result : Option[LoanedKey] = obj.Restrict(5)
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object mustEqual None
result.get.Object = None //assignment 1
result.get.Object mustEqual None //still unassigned
result.get.Object = test1 //assignment 2
result.get.Object mustEqual Some(test1)
result.get.Object = test2 //assignment 3
result.get.Object mustEqual Some(test1) //same as above
}
"return a restricted number (correctly fail)" in {
val obj = MaxNumberSource()
val test = new TestClass()
val result : Option[LoanedKey] = obj.Restrict(5)
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object = test
obj.Return(5)
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Restricted
result2.get.Object mustEqual Some(test)
}
"restrict a previously-assigned number" in {
val obj = MaxNumberSource()
val test = new TestClass()
val result1 : Option[LoanedKey] = obj.Available(5)
result1.isDefined mustEqual true
result1.get.Policy mustEqual AvailabilityPolicy.Leased
result1.get.Object = test
val result2 : Option[LoanedKey] = obj.Restrict(5)
result2.isDefined mustEqual true
result2.get.Policy mustEqual AvailabilityPolicy.Restricted
result2.get.Object mustEqual Some(test)
}
"check a number (not previously gotten)" in {
val obj = MaxNumberSource()
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Available
result2.get.Object mustEqual None
}
"check a number (previously gotten)" in {
val obj = MaxNumberSource()
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object mustEqual None
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object mustEqual None
}
"check a number (assigned)" in {
val obj = MaxNumberSource()
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object = new TestClass()
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object mustEqual result.get.Object
}
"check a number (assigned and returned)" in {
val obj = MaxNumberSource()
val test = new TestClass()
val result : Option[LoanedKey] = obj.Available(5)
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object = test
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object.get === test
obj.Return(5) mustEqual Some(test)
val result3 : Option[SecureKey] = obj.Get(5)
result3.get.Policy mustEqual AvailabilityPolicy.Available
result3.get.Object mustEqual None
}
"clear" in {
val obj = MaxNumberSource()
val test1 = new TestClass()
val test2 = new TestClass()
obj.Available(5) //no assignment
obj.Available(10).get.Object = test1
obj.Available(15).get.Object = test2
obj.Restrict(15)
obj.Restrict(20).get.Object = test1
obj.CountUsed mustEqual 4
val list : List[IdentifiableEntity] = obj.Clear()
obj.CountUsed mustEqual 0
list.size mustEqual 3
list.count(obj => { obj == test1 }) mustEqual 2
list.count(obj => { obj == test2 }) mustEqual 1
}
}
"LimitedNumberSource" should {
import net.psforever.objects.guid.source.LimitedNumberSource
"construct" in {
val obj = LimitedNumberSource(25)
obj.Size mustEqual 26
obj.CountAvailable mustEqual 26
obj.CountUsed mustEqual 0
}
"get a number" in {
val obj = LimitedNumberSource(25)
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object mustEqual None
obj.Size mustEqual 26
obj.CountAvailable mustEqual 25
obj.CountUsed mustEqual 1
}
"assign the number" in {
val obj = LimitedNumberSource(25)
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.Object = new TestClass()
ok
}
"return a number (unused)" in {
val obj = LimitedNumberSource(25)
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
obj.CountUsed mustEqual 1
val ret = obj.Return(result.get)
ret mustEqual None
obj.CountUsed mustEqual 0
}
"return a number (assigned)" in {
val obj = LimitedNumberSource(25)
val test = new TestClass()
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Object = test
obj.CountUsed mustEqual 1
val ret = obj.Return(result.get)
ret mustEqual Some(test)
obj.CountUsed mustEqual 0
}
"restrict a number (unassigned)" in {
val obj = LimitedNumberSource(25)
val result : Option[LoanedKey] = obj.Restrict(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object mustEqual None
}
"restrict a number (assigned + multiple assignments)" in {
val obj = LimitedNumberSource(25)
val test1 = new TestClass()
val test2 = new TestClass()
val result : Option[LoanedKey] = obj.Restrict(5)
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object mustEqual None
result.get.Object = None //assignment 1
result.get.Object mustEqual None //still unassigned
result.get.Object = test1 //assignment 2
result.get.Object mustEqual Some(test1)
result.get.Object = test2 //assignment 3
result.get.Object mustEqual Some(test1) //same as above
}
"return a restricted number (correctly fail)" in {
val obj = LimitedNumberSource(25)
val test = new TestClass()
val result : Option[LoanedKey] = obj.Restrict(5)
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object = test
obj.Return(5)
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Restricted
result2.get.Object mustEqual Some(test)
}
"restrict a previously-assigned number" in {
val obj = LimitedNumberSource(25)
val test = new TestClass()
val result1 : Option[LoanedKey] = obj.Available(5)
result1.isDefined mustEqual true
result1.get.Policy mustEqual AvailabilityPolicy.Leased
result1.get.Object = test
val result2 : Option[LoanedKey] = obj.Restrict(5)
result2.isDefined mustEqual true
result2.get.Policy mustEqual AvailabilityPolicy.Restricted
result2.get.Object mustEqual Some(test)
}
"check a number (not previously gotten)" in {
val obj = LimitedNumberSource(25)
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Available
result2.get.Object mustEqual None
}
"check a number (previously gotten)" in {
val obj = LimitedNumberSource(25)
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object mustEqual None
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object mustEqual None
}
"check a number (assigned)" in {
val obj = LimitedNumberSource(25)
val result : Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object = new TestClass()
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object mustEqual result.get.Object
}
"check a number (assigned and returned)" in {
val obj = LimitedNumberSource(25)
val test = new TestClass()
val result : Option[LoanedKey] = obj.Available(5)
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object = test
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object.get mustEqual test
obj.Return(5) mustEqual Some(test)
val result3 : Option[SecureKey] = obj.Get(5)
result3.get.Policy mustEqual AvailabilityPolicy.Available
result3.get.Object mustEqual None
}
"clear" in {
val obj = LimitedNumberSource(25)
val test1 = new TestClass()
val test2 = new TestClass()
obj.Available(5) //no assignment
obj.Available(10).get.Object = test1
obj.Available(15).get.Object = test2
obj.Restrict(15)
obj.Restrict(20).get.Object = test1
obj.CountUsed mustEqual 4
val list : List[IdentifiableEntity] = obj.Clear()
obj.CountUsed mustEqual 0
list.size mustEqual 3
list.count(obj => obj == test1) mustEqual 2
list.count(obj => obj == test2) mustEqual 1
}
}
}

View file

@ -0,0 +1,153 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.{Implant, Player, SimpleItem}
import net.psforever.objects.definition.{ImplantDefinition, SimpleItemDefinition}
import net.psforever.objects.equipment.EquipmentSize
import net.psforever.types.{CharacterGender, ExoSuitType, ImplantType, PlanetSideEmpire}
import org.specs2.mutable._
class PlayerTest extends Specification {
"construct" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.isAlive mustEqual false
}
"(re)spawn" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.isAlive mustEqual false
obj.Health mustEqual 0
obj.Stamina mustEqual 0
obj.Armor mustEqual 0
obj.Spawn
obj.isAlive mustEqual true
obj.Health mustEqual obj.MaxHealth
obj.Stamina mustEqual obj.MaxStamina
obj.Armor mustEqual obj.MaxArmor
}
"init (Standard Exo-Suit)" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.ExoSuit mustEqual ExoSuitType.Standard
obj.Slot(0).Size mustEqual EquipmentSize.Pistol
obj.Slot(1).Size mustEqual EquipmentSize.Blocked
obj.Slot(2).Size mustEqual EquipmentSize.Rifle
obj.Slot(3).Size mustEqual EquipmentSize.Blocked
obj.Slot(4).Size mustEqual EquipmentSize.Melee
obj.Inventory.Width mustEqual 9
obj.Inventory.Height mustEqual 6
obj.Inventory.Offset mustEqual 6
}
"die" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Spawn
obj.Armor = 35 //50 -> 35
obj.isAlive mustEqual true
obj.Health mustEqual obj.MaxHealth
obj.Stamina mustEqual obj.MaxStamina
obj.Armor mustEqual 35
obj.Die
obj.isAlive mustEqual false
obj.Health mustEqual 0
obj.Stamina mustEqual 0
obj.Armor mustEqual 35
}
"draw equipped holsters only" in {
val wep = SimpleItem(SimpleItemDefinition(149))
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Slot(1).Size = EquipmentSize.Pistol
obj.Slot(1).Equipment = wep
obj.DrawnSlot mustEqual Player.HandsDownSlot
obj.DrawnSlot = 0
obj.DrawnSlot mustEqual Player.HandsDownSlot
obj.DrawnSlot = 1
obj.DrawnSlot mustEqual 1
}
"remember the last drawn holster" in {
val wep1 = SimpleItem(SimpleItemDefinition(149))
val wep2 = SimpleItem(SimpleItemDefinition(149))
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Slot(0).Size = EquipmentSize.Pistol
obj.Slot(0).Equipment = wep1
obj.Slot(1).Size = EquipmentSize.Pistol
obj.Slot(1).Equipment = wep2
obj.DrawnSlot mustEqual Player.HandsDownSlot //default value
obj.LastDrawnSlot mustEqual 0 //default value
obj.DrawnSlot = 1
obj.DrawnSlot mustEqual 1
obj.LastDrawnSlot mustEqual 0 //default value; sorry
obj.DrawnSlot = 0
obj.DrawnSlot mustEqual 0
obj.LastDrawnSlot mustEqual 1
obj.DrawnSlot = Player.HandsDownSlot
obj.DrawnSlot mustEqual Player.HandsDownSlot
obj.LastDrawnSlot mustEqual 0
obj.DrawnSlot = 1
obj.DrawnSlot mustEqual 1
obj.LastDrawnSlot mustEqual 0
obj.DrawnSlot = 0
obj.DrawnSlot mustEqual 0
obj.LastDrawnSlot mustEqual 1
obj.DrawnSlot = 1
obj.DrawnSlot mustEqual 1
obj.LastDrawnSlot mustEqual 0
obj.DrawnSlot = Player.HandsDownSlot
obj.DrawnSlot mustEqual Player.HandsDownSlot
obj.LastDrawnSlot mustEqual 1
}
"install no implants until a slot is unlocked" in {
val testplant : Implant = Implant(ImplantDefinition(1))
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Implants(0).Unlocked mustEqual false
obj.Implant(0) mustEqual None
obj.InstallImplant(testplant)
obj.Implant(0) mustEqual None
obj.Implant(ImplantType(1)) mustEqual None
obj.Implants(0).Unlocked = true
obj.InstallImplant(testplant)
obj.Implant(0) mustEqual Some(testplant.Definition.Type)
obj.Implant(ImplantType(1)) mustEqual Some(testplant)
}
"uninstall implants" in {
val testplant : Implant = Implant(ImplantDefinition(1))
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Implants(0).Unlocked = true
obj.InstallImplant(testplant)
obj.Implant(ImplantType(1)) mustEqual Some(testplant)
obj.UninstallImplant(ImplantType(1))
obj.Implant(0) mustEqual None
obj.Implant(ImplantType(1)) mustEqual None
}
"administrate" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Admin mustEqual false
Player.Administrate(obj, true)
obj.Admin mustEqual true
Player.Administrate(obj, false)
obj.Admin mustEqual false
}
"spectate" in {
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
obj.Spectator mustEqual false
Player.Spectate(obj, true)
obj.Spectator mustEqual true
Player.Spectate(obj, false)
obj.Spectator mustEqual false
}
}