mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-03-13 17:10:33 +00:00
new stuff for player server classes; this update is not yet complete
adjusted sample Reload code and added insertion and removal functions for inventory more work on player classes; moving PacketResolution to another branch decoupling GUIDs from objects; introduced Ammo enum; minor adjustments to inventory system; different object/class hierarchy transferring basic files from another branch converted from get/set to accessor/mutator; resolved conflict from name changes refactored basic components such as GUID and location/orientation utilities kludge; more fields are given accessor and mutators; create package for vehicle-specific classes GUID assurance, now with less object creation test files; changes to how AmmoBox initializes sorry, a little bit of everything, so much I forgot to write it all down switched to a unified fire mode object internal to a Tool importing a heavily modified version of my GUID manager objects from the laternate branch; not finished or tested yet created a Trait to make Key private, sources and selectors to allow NumberPools to exist independent of a NumberSource; placed Ascending into a misc folder swapped the Return methods for selectors so that the more primitive logic is the one that needs to be overriden; renamed a selector to be more common; had to update some copyright messages fixed major logic issue with NumberPool; added comments to NumberSource files NumberSource tests simplified and made more consistent the method naming convention of NumberSources comments for NumberSelectors starting on NumberSelector tests modifications that should better support number pools; added a pool hub that acts on a predefined source adjustment to how Tools and FireModeDefintion keep track of ammunition and ammunition slots; I don't think this is sufficient small additions to Tools; filled out simple tests for other three Selectors added object lookup notation for the pool hub added more NumberSelector tests; removed the word 'Number' from subclass names re-named classes, re-packaged classes, re-named packages; created new Selector, split pools to create a fallback for the NumberPoolHub changes to NumberPool classes; tests on NumberPool classes changes to NumberPool classes; tests on NumberPool classes2 some robust testing for NumberPoolHub, plus necessary modifications to other files register and unregister functions now use Success and Failure conditions, save for one true thrown Exception reduced the flow of certain algorithm chains, mainly by adding match statements and removing Exceptions error message text the same thing as the last commit, but with NumberPools rather than NumberPoolHub various types of freeform registration added sorting functions to Selectors to allow for hotswapping for number pools, especially to and from SpecificSelector; tests for NumberPoolHub get numbers from an Array of indices, not the list of Numbers, in SimplePool added a class to represent the four types of recovery kits comments on Kit files created package for supporting equipment classes; renamed /definition/ package adding class for items that construct deployables, the router telepad included added SimpleItem, classes for game Equipment that do not have internal state; re-organized ObjectDefinition files and the game objects they create to more naturally move around EquipmentSize and InventoryTile (size) added SimpleItem tests (what they are...); removed example code that has hogging an import from AmmoBox auto-sort for loading and fitting former inventory content back into the inventory method of finding first available position to fit an certain size block in the inventory changed CheckCollision return type to provide Try[List[Int]; fixed all existing references and tests wrote comments for GridInventory methods; changed insertion param to be of form 'key -> element' adding features to Player; created definitions for Player class; re-grouped ConstructionItem enumerations initial work on implants; shuffled classes to better accommodate the new implant system, I think wrote some tests for Implants; fixing Implant logic wrote tests for Player class and made adjustments where necessary basic initialization during Player creation based on exo-suit type three wrapper Actors for the normal classes comments on code modified tests to improve accountability; added Resolver class to deal with multiple tasks that contribute to a larger task changed Tools to an internal AmmoBox; don't have to def -= symbol if I def _= symbol LivePlayerList -> MasterPlayerList, and added a Fit def for Player that checks holsters as well as inventory example of packet conversion can be found with AmmoBoxDefinition added conversion for ToolDefinition added all Equipment packet conversion functionality; started working on Avatar-related conversions continued effort towards a working Player packet conversion test subclasses of Equipment apparently do not need to overide the type of the PacketConverter for generics the logical conclusion: it doesn't matter what generics Packet returns so long as it returns an ObjectCreateConverter[] type separated converters from definitions into files changed some configuration information to final; added a bunch of converters, not fully tested though changed function names in converters replaced WSA packet-driven OCDM with Player object OCDM; upgrade to Float angular data added partial support for LockerContainer; changed Equipment defaults to a common value changes to AvatarConverter to include 5th slot; changes to VehicleConverter to make work; implementation of Fury in Vehicle->packet example in WSA added a seat definition and renovated how the weapon controlled from a seat can be found comments to files mainly; non-essential functionality to some classes, mostly access determination moved converter tests to their own test file write more of this test added ServiceManager, as it is useful pool range changes added AvatarService, as it is useful straightened out the GUID actors; added the static method for adding AmmoBoxes (to be converted later) chnages to task resolution operation complicated Task and TaskResolver logic is now possible; for example, you can schedule giving an AmmoBox a GUID, before giving a Tool a GUID, before placing the Tool in a player's hand; see Suppressor example in WSA separated the Task trait and the TaskResolver actor into their own classes, moving the former RegistrationTaskResolver class into the /misc/ folder; deleted old backup copy of HubActor; modifications for PoC and supported tests added better support and protection against putting things in the wrong hand when using inventories and the Player.Slot(n) function GlobalDefinitions file; added laze pointer as an SItem, and gave it the command detonater management code; additionally fixed spelling of 'detonat[o]r' in Codec; early Terminal class work updated tests to GlobalDefinitions entries; Terminal works but I don't like it played with GUID pooling workflow, though to little avail; modifications to Terminal purchasing workflow, but still very volatile modified NumberPoolActor and NumberPoolAccessor to make them more straightforward and not use akka ask as a go-between fixed recovery options so that they do not cause more messages trailing newline InventoryItem (packet data) renamed InventoryItemData to remove ambiguity; Terminal functionality improved, allowing for swapping of exo-suits and the restoration of equipment positions remove yet-unsupported Terminal messaging made Terminal message more specific; can now put equipment into empty slot on exo-suit change; should report changes better re-organized function calls to preserved items removed from holster slots on exo-suit change moved predicate to the end of the list of params for recoverInventory so that repetition can be eliminated and a default value can be assigned issues with making Tool; committing changes before revert of NumberPoolActor and NumberPoolAccessorActor to see if those broke it a necessary evil, the reverting of these two Actors; subtask resolution does not work unless I do so, for now restored the registration portion of tasking back to where it previously was (and better?) NumberPoolActor and the ...AccessorActor are back to a comfortable place (and better?) re-draw object in hand when switching exo-suits; build AmmoBoxes for Tool during Terminal-controlled creation, not Tool-controlled creation order of task cleanup reversed to avoid index mismatch; added itsm to TerminalDefinition common 5x5 AmmoBox size; added vehicle weapon ammo boxes to terminal added error catching messages; stopped odd double-registering issue early resolved issue where multiple subtasks started their main task multiple times; added checks that an object does not register a new GUID when it already has one wrote unregistration code for Selling items back through the Terminal, repairing logic along the way; also, wrote a top-level GUID find for the Player for use of MoveItem added framework for starting on Loadouts; managed issue with parent tasks starting before being summoned by child subtasks, often resulting in the complete skip of the execution phase of the parent; refactored registration tasks in WSA modified Tool structure, exposing the AmmoSlot list a bit more stuff stuff Tool ammo slot changes to default and comments basic loadout framework for Infantry; need to integrate initial work on FavoritesRequest packet tests for FavoritesRequest packet increased size of number pool for testing; wrote an algorithm that translates to and from the simplified version of objects stored in loadouts refactored the tasking for adding Equipment and removing Equipment updated the inventory so the Map of items does not have to rely on the GUID of an item being set before the item is inserted untested routine for registering a player character; pushing all changes before making significant changes to the client init code structure added to comments of BeginZoningMessage; transitioned player through and initial step of a more proper login GUID association the current avatar is properly registered and there is something of a workflow with the messages and packets corrected another bit of logic where inventories used to be indexed by object GUID in AvatarConverter; reversed unregister-remove task sequence such that GUID-less object is not allowed to exist in a stable object hierarchy working Loadout loading added identification functions to GlobalDefinitions; echo ObjectDelete back to client accidentally got rid of something in WSA, but now restored; adding extra details to Terminal operations separated Terminal into separate files and moved files into their own package under \objects\ for now; can delete loadouts now in WSA better handling of ReloadMessage and MoveItemMessage framework for better support involving dropping and picking up items code comments and small modifications, such as the location and structure of the Terminal Equipment definitions wrote comments in GlobalDefinitions; modified code so that a primitive form of player synchronization now occurs for future testing added code to display already-dropped Equipment on the ground; limitations are explained; moved TaskResolver to more a global location, though I don't know if that helps modified avatar unregister logic to ensure vacating player is deleted from other clients 'properly' more comments; improved checks for MoveItemMessage; squared distances as necessary subtle changes to login scripting so that test character is always offered re-organizing the functions in WSA so that only the local objects separate the two message processing blocks
This commit is contained in:
parent
9a8e1e8f95
commit
4bcef8ce98
134 changed files with 13169 additions and 225 deletions
200
common/src/test/scala/objects/ConverterTest.scala
Normal file
200
common/src/test/scala/objects/ConverterTest.scala
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
83
common/src/test/scala/objects/EntityTest.scala
Normal file
83
common/src/test/scala/objects/EntityTest.scala
Normal 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 Vector3(0f, 0f, 0f)
|
||||
}
|
||||
|
||||
"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 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]
|
||||
}
|
||||
}
|
||||
}
|
||||
258
common/src/test/scala/objects/EquipmentTest.scala
Normal file
258
common/src/test/scala/objects/EquipmentTest.scala
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
76
common/src/test/scala/objects/ImplantTest.scala
Normal file
76
common/src/test/scala/objects/ImplantTest.scala
Normal 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
|
||||
}
|
||||
}
|
||||
215
common/src/test/scala/objects/InventoryTest.scala
Normal file
215
common/src/test/scala/objects/InventoryTest.scala
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
// 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
|
||||
obj.CheckCollisionsAsList(0, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(1, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(2, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(3, w, h) mustEqual Success(Nil)
|
||||
obj.CheckCollisionsAsGrid(0, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(1, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(2, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(3, w, h) mustEqual Success(Nil)
|
||||
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
|
||||
obj.CheckCollisionsAsList(3, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(2, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(1, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(0, w, h) mustEqual Success(Nil)
|
||||
obj.CheckCollisionsAsGrid(3, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(2, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(1, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(0, w, h) mustEqual Success(Nil)
|
||||
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
|
||||
obj.CheckCollisionsAsList(0, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(9, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(18, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(27, w, h) mustEqual Success(Nil)
|
||||
obj.CheckCollisionsAsGrid(0, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(9, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(18, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(27, w, h) mustEqual Success(Nil)
|
||||
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
|
||||
obj.CheckCollisionsAsList(27, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(19, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(9, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsList(0, w, h) mustEqual Success(Nil)
|
||||
obj.CheckCollisionsAsGrid(27, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(19, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(9, w, h) mustEqual Success(1 :: Nil)
|
||||
obj.CheckCollisionsAsGrid(0, w, h) mustEqual Success(Nil)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
73
common/src/test/scala/objects/NumberPoolActorTest.scala
Normal file
73
common/src/test/scala/objects/NumberPoolActorTest.scala
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.{ActorSystem, Props}
|
||||
import akka.pattern.ask
|
||||
import akka.util.Timeout
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import net.psforever.objects.entity.IdentifiableEntity
|
||||
import net.psforever.objects.guid.NumberPoolHub
|
||||
import net.psforever.objects.guid.actor._
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
import net.psforever.objects.guid.pool.ExclusivePool
|
||||
import net.psforever.objects.guid.selector.RandomSelector
|
||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
import scala.concurrent.Await
|
||||
import scala.util.{Failure, Try}
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
class NumberPoolActorTest extends Specification {
|
||||
val config : java.util.Map[String,Object] = Map(
|
||||
"akka.loggers" -> List("akka.event.slf4j.Slf4jLogger").asJava,
|
||||
"akka.loglevel" -> "INFO",
|
||||
"akka.logging-filter" -> "akka.event.slf4j.Slf4jLoggingFilter"
|
||||
).asJava
|
||||
implicit val timeout = Timeout(100 milliseconds)
|
||||
|
||||
class TestEntity extends IdentifiableEntity
|
||||
|
||||
"NumberPoolActor" in {
|
||||
val system : akka.actor.ActorSystem = ActorSystem("ActorTest", ConfigFactory.parseMap(config))
|
||||
val pool = new ExclusivePool((25 to 50).toList)
|
||||
pool.Selector = new RandomSelector
|
||||
val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor")
|
||||
val future = (poolActor ? NumberPoolActor.GetAnyNumber()).mapTo[Try[Int]]
|
||||
future.onComplete(value => {
|
||||
system.terminate
|
||||
value.foreach {
|
||||
case Failure(_) =>
|
||||
ko
|
||||
case _ => ;
|
||||
}
|
||||
})
|
||||
Await.result(system.whenTerminated, Duration.Inf)
|
||||
ok
|
||||
}
|
||||
|
||||
"NumberPoolAccessorActor" in {
|
||||
/*
|
||||
Notes:
|
||||
Receiver sets resultObject.complete to true and shuts down the ActorSystem.
|
||||
If Receiver never gets the appropriate message, Await.result will timeout (and the exception will be caught safely).
|
||||
*/
|
||||
val system : akka.actor.ActorSystem = ActorSystem("ActorTest", ConfigFactory.parseMap(config))
|
||||
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 resultObject = new ResolutionObject
|
||||
resultObject.complete mustEqual false
|
||||
val receiver = system.actorOf(Props(classOf[Receiver], system, resultObject), "receiver")
|
||||
|
||||
val obj : TestEntity = new TestEntity
|
||||
poolAccessor ! Register(obj, receiver)
|
||||
try { Await.result(system.whenTerminated, 5 seconds) } catch { case _ : Exception => ; }
|
||||
resultObject.complete mustEqual true
|
||||
}
|
||||
}
|
||||
285
common/src/test/scala/objects/NumberPoolHubTest.scala
Normal file
285
common/src/test/scala/objects/NumberPoolHubTest.scala
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
194
common/src/test/scala/objects/NumberPoolTest.scala
Normal file
194
common/src/test/scala/objects/NumberPoolTest.scala
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
326
common/src/test/scala/objects/NumberSelectorTest.scala
Normal file
326
common/src/test/scala/objects/NumberSelectorTest.scala
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
359
common/src/test/scala/objects/NumberSourceTest.scala
Normal file
359
common/src/test/scala/objects/NumberSourceTest.scala
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
153
common/src/test/scala/objects/PlayerTest.scala
Normal file
153
common/src/test/scala/objects/PlayerTest.scala
Normal 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
|
||||
}
|
||||
}
|
||||
28
common/src/test/scala/objects/Receiver.scala
Normal file
28
common/src/test/scala/objects/Receiver.scala
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.{Actor, ActorSystem}
|
||||
import net.psforever.objects.entity.IdentifiableEntity
|
||||
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
class ResolutionObject {
|
||||
var complete = false
|
||||
}
|
||||
|
||||
/**
|
||||
* This is for file NumberPoolActorTest, for its tests.
|
||||
* Attempting to define this class in the aforementioned file causes a "can not find constructor" issue.
|
||||
*/
|
||||
class Receiver(private val system : ActorSystem, result : ResolutionObject) extends Actor {
|
||||
def receive : Receive = {
|
||||
case Success(objct : IdentifiableEntity) =>
|
||||
objct.GUID //this will throw a NoGUIDException if it fails
|
||||
result.complete = true
|
||||
system.terminate()
|
||||
case Failure(ex) =>
|
||||
org.log4s.getLogger.error(s"object did not register - ${ex.getMessage}")
|
||||
system.terminate()
|
||||
}
|
||||
}
|
||||
//TODO Look into whether that was a legitimate issue or whether I (the user) was in error during Actor initialization later.
|
||||
Loading…
Add table
Add a link
Reference in a new issue