registered object retain their GUID after being unregistered

This commit is contained in:
FateJH 2020-01-05 23:24:26 -05:00 committed by pschord
parent ae7f8bf71d
commit f9414a6798
9 changed files with 116 additions and 65 deletions

View file

@ -9,25 +9,42 @@ import net.psforever.packet.game.PlanetSideGUID
* "Testing" the object refers to the act of acquiring a reference to the GUID the object is using.
* This object starts with a container class that represents a unprepared GUID state and raises an `Exception` when tested.
* Setting a proper `PlanetSideGUID` replaces that container class with a container class that returns the GUID when tested.
* The object can be invalidated, restoring the previous `Exception`-raising condition.
* @throws `NoGUIDException` if there is no GUID to give
* The object can be invalidated, retaining the previous identifier number, but marking that object as being "stale."
* "Staleness" is a property indicating whether or not the number can be used as a valid representation of the object.
* @throws `NoGUIDException` if a GUID has not yet been assigned
*/
abstract class IdentifiableEntity extends Identifiable {
/** indicate the validity of the current GUID */
private var stale : Boolean = true
/** storage for the active GUID */
private val container : GUIDContainable = GUIDContainer()
/** the handle for the active GUID; starts as exception-throwing */
private var current : GUIDContainable = IdentifiableEntity.noGUIDContainer
def HasGUID : Boolean = current ne IdentifiableEntity.noGUIDContainer
/**
* The object will not originally having a valid GUID,
* so "stale" will be used to expressed "not initialized."
* After being set and then properly invalidated, then it will indicate proper staleness.
* @return whether the value of the GUID is a valid representation for this object
*/
def HasGUID : Boolean = !stale
def GUID : PlanetSideGUID = current.GUID
def GUID_=(guid : PlanetSideGUID) : PlanetSideGUID = {
stale = false
current = container
current.GUID = guid
GUID
}
/**
* Set the staleness to indicate whether the GUID has ever been set
* or that the set GUID is not a proper representation of the object.
* It is always set to `true`.
*/
def Invalidate() : Unit = {
current = IdentifiableEntity.noGUIDContainer
stale = true
}
}
@ -50,7 +67,7 @@ private case class NoGUIDContainer() extends GUIDContainable {
* @return never returns
*/
def GUID : PlanetSideGUID = {
throw NoGUIDException("object has not initialized a global identifier")
throw NoGUIDException(s"object $this has not initialized a global identifier")
}
/**

View file

@ -106,14 +106,16 @@ class EntityTest extends Specification {
ok
}
"error while unset" in {
"error while not set" in {
val obj : EntityTestClass = new EntityTestClass
obj.HasGUID mustEqual false
obj.GUID must throwA[NoGUIDException]
}
"work after mutation" in {
val obj : EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.HasGUID mustEqual true
obj.GUID mustEqual PlanetSideGUID(1051)
}
@ -127,12 +129,43 @@ class EntityTest extends Specification {
obj.GUID mustEqual PlanetSideGUID(62)
}
"invalidate and resume error" in {
"invalidate and report as not having a GUID, but continue to work" in {
val obj : EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.HasGUID mustEqual true
obj.GUID mustEqual PlanetSideGUID(1051)
obj.Invalidate()
obj.GUID must throwA[NoGUIDException]
obj.HasGUID mustEqual false
obj.GUID mustEqual PlanetSideGUID(1051)
}
"assign a new GUID after invalidation and continue to work" in {
val obj : EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.HasGUID mustEqual true
obj.GUID mustEqual PlanetSideGUID(1051)
obj.Invalidate()
obj.GUID mustEqual PlanetSideGUID(1051)
obj.HasGUID mustEqual false
obj.GUID = PlanetSideGUID(1052)
obj.HasGUID mustEqual true
obj.GUID mustEqual PlanetSideGUID(1052)
}
"assignthe same GUID after invalidation and continue to work" in {
val obj : EntityTestClass = new EntityTestClass
val guid = new PlanetSideGUID(1051)
obj.GUID = guid
obj.HasGUID mustEqual true
obj.GUID mustEqual guid
obj.Invalidate()
obj.GUID mustEqual guid
obj.HasGUID mustEqual false
obj.GUID = guid
obj.HasGUID mustEqual true
obj.GUID mustEqual guid
}
}
}

View file

@ -1,7 +1,7 @@
// Copyright (c) 2017 PSForever
package objects.number
import akka.actor.{ActorSystem, Props}
import akka.actor.Props
import base.ActorTest
import net.psforever.objects.guid.actor.NumberPoolActor
import net.psforever.objects.guid.pool.ExclusivePool

View file

@ -55,7 +55,7 @@ class NumberPoolHubTest extends Specification {
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
obj.GetPool("fibonacci").isEmpty mustEqual true
}
"block removing the default 'generic' pool" in {
@ -101,7 +101,7 @@ class NumberPoolHubTest extends Specification {
hub.register(obj, "fibonacci") match {
case Success(number) =>
val objFromNumber = hub(number)
objFromNumber mustEqual Some(obj)
objFromNumber.contains(obj) mustEqual true
case _ =>
ko
}
@ -111,7 +111,7 @@ class NumberPoolHubTest extends Specification {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci1", numberList1)
hub.AddPool("fibonacci2", numberList2)
hub.WhichPool(13) mustEqual Some("fibonacci2")
hub.WhichPool(13).contains("fibonacci2") mustEqual true
}
"lookup the pool of a registered object" in {
@ -119,7 +119,7 @@ class NumberPoolHubTest extends Specification {
hub.AddPool("fibonacci", numberList1)
val obj = new EntityTestClass()
hub.register(obj, "fibonacci")
hub.WhichPool(obj) mustEqual Some("fibonacci")
hub.WhichPool(obj).contains("fibonacci") mustEqual true
}
"register an object to a specific, unused number; it is assigned to pool 'generic'" in {
@ -130,7 +130,7 @@ class NumberPoolHubTest extends Specification {
hub.register(obj, 44) match {
case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number)
hub.WhichPool(obj) mustEqual Some("generic")
hub.WhichPool(obj).contains("generic") mustEqual true
case _ =>
ko
}
@ -145,8 +145,8 @@ class NumberPoolHubTest extends Specification {
hub.register(obj, 5) match {
case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number)
hub.WhichPool(obj) mustEqual Some("fibonacci")
src.Available(5) mustEqual None
hub.WhichPool(obj).contains("fibonacci") mustEqual true
src.Available(5).isEmpty mustEqual true
case _ =>
ko
}
@ -161,8 +161,8 @@ class NumberPoolHubTest extends Specification {
hub.register(obj, 13) match {
case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number)
hub.WhichPool(obj) mustEqual Some("fibonacci")
src.Available(13) mustEqual None
hub.WhichPool(obj).contains("fibonacci") mustEqual true
src.Available(13).isEmpty mustEqual true
case _ =>
ko
}
@ -172,20 +172,21 @@ class NumberPoolHubTest extends Specification {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
val obj = new EntityTestClass()
hub.register(obj)
hub.WhichPool(obj) mustEqual Some("generic")
hub.WhichPool(obj).contains("generic") mustEqual true
}
"unregister an object" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass()
obj.HasGUID mustEqual false
hub.register(obj, "fibonacci")
hub.WhichPool(obj) mustEqual Some("fibonacci")
try { obj.GUID } catch { case _ : Exception => ko } //passes
hub.WhichPool(obj).contains("fibonacci") mustEqual true
obj.HasGUID mustEqual true
hub.unregister(obj)
hub.WhichPool(obj) mustEqual None
obj.GUID must throwA[Exception] //fails
obj.HasGUID mustEqual false
hub.WhichPool(obj).isEmpty mustEqual true
}
"not register an object to a different pool" in {
@ -247,14 +248,15 @@ class NumberPoolHubTest extends Specification {
hub.register(13) match {
case Success(key) =>
key.Object = obj
obj.HasGUID mustEqual true
case _ =>
ko
}
hub.WhichPool(obj) mustEqual Some("fibonacci")
hub.WhichPool(obj).contains("fibonacci") mustEqual true
hub.unregister(13) match {
case Success(thing) =>
thing mustEqual Some(obj)
thing.get.GUID must throwA[Exception]
thing.contains(obj) mustEqual true
thing.get.HasGUID mustEqual false
case _ =>
ko
}

View file

@ -158,10 +158,10 @@ class NumberPoolTest extends Specification {
val obj = new GenericPool(map, 11)
obj.Selector.asInstanceOf[SpecificSelector].SelectionIndex = 5
obj.Get()
map.get(5) mustEqual Some("generic")
map.get(5).contains("generic") mustEqual true
obj.Numbers.contains(5) mustEqual true
obj.Return(5) mustEqual true
map.get(5) mustEqual None
map.get(5).isEmpty mustEqual true
obj.Numbers.isEmpty mustEqual true
}

View file

@ -25,7 +25,7 @@ class NumberSourceTest extends Specification {
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object mustEqual None
result.get.Object.isEmpty mustEqual true
obj.Size mustEqual 26
obj.CountAvailable mustEqual 25
obj.CountUsed mustEqual 1
@ -46,7 +46,7 @@ class NumberSourceTest extends Specification {
result.get.GUID mustEqual 5
obj.CountUsed mustEqual 1
val ret = obj.Return(result.get)
ret mustEqual None
ret.isEmpty mustEqual true
obj.CountUsed mustEqual 0
}
@ -59,7 +59,7 @@ class NumberSourceTest extends Specification {
result.get.Object = test
obj.CountUsed mustEqual 1
val ret = obj.Return(result.get)
ret mustEqual Some(test)
ret.contains(test) mustEqual true
obj.CountUsed mustEqual 0
}
@ -69,7 +69,7 @@ class NumberSourceTest extends Specification {
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object mustEqual None
result.get.Object.isEmpty mustEqual true
}
"restrict a number (assigned + multiple assignments)" in {
@ -79,13 +79,13 @@ class NumberSourceTest extends Specification {
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.isEmpty mustEqual true
result.get.Object = None //assignment 1
result.get.Object mustEqual None //still unassigned
result.get.Object.isEmpty mustEqual true //still unassigned
result.get.Object = test1 //assignment 2
result.get.Object mustEqual Some(test1)
result.get.Object.contains(test1) mustEqual true
result.get.Object = test2 //assignment 3
result.get.Object mustEqual Some(test1) //same as above
result.get.Object.contains(test1) mustEqual true //same as above
}
"return a restricted number (correctly fail)" in {
@ -100,7 +100,7 @@ class NumberSourceTest extends Specification {
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Restricted
result2.get.Object mustEqual Some(test)
result2.get.Object.contains(test) mustEqual true
}
"return a secure key" in {
@ -111,7 +111,7 @@ class NumberSourceTest extends Specification {
test.GUID = PlanetSideGUID(5)
val result2 : Option[SecureKey] = obj.Get(5)
obj.Return(result2.get) mustEqual Some(test)
obj.Return(result2.get).contains(test) mustEqual true
}
"restrict a previously-assigned number" in {
@ -124,7 +124,7 @@ class NumberSourceTest extends Specification {
val result2 : Option[LoanedKey] = obj.Restrict(5)
result2.isDefined mustEqual true
result2.get.Policy mustEqual AvailabilityPolicy.Restricted
result2.get.Object mustEqual Some(test)
result2.get.Object.contains(test) mustEqual true
}
"check a number (not previously gotten)" in {
@ -132,7 +132,7 @@ class NumberSourceTest extends Specification {
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Available
result2.get.Object mustEqual None
result2.get.Object.isEmpty mustEqual true
}
"check a number (previously gotten)" in {
@ -141,11 +141,11 @@ class NumberSourceTest extends Specification {
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object mustEqual None
result.get.Object.isEmpty mustEqual true
val result2 : Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object mustEqual None
result2.get.Object.isEmpty mustEqual true
}
"check a number (assigned)" in {
@ -170,10 +170,10 @@ class NumberSourceTest extends Specification {
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)
obj.Return(5).contains(test) mustEqual true
val result3 : Option[SecureKey] = obj.Get(5)
result3.get.Policy mustEqual AvailabilityPolicy.Available
result3.get.Object mustEqual None
result3.get.Object.isEmpty mustEqual true
}
"clear" in {

View file

@ -12,49 +12,49 @@ class RegisterTest extends Specification {
"construct (object)" in {
val reg = Register(obj)
reg.obj mustEqual obj
reg.number mustEqual None
reg.name mustEqual None
reg.callback mustEqual None
reg.number.isEmpty mustEqual true
reg.name.isEmpty mustEqual true
reg.callback.isEmpty mustEqual true
}
"construct (object, callback)" in {
val reg = Register(obj, Actor.noSender)
reg.obj mustEqual obj
reg.number mustEqual None
reg.name mustEqual None
reg.callback mustEqual Some(Actor.noSender)
reg.number.isEmpty mustEqual true
reg.name.isEmpty mustEqual true
reg.callback.contains(Actor.noSender) mustEqual true
}
"construct (object, suggested number)" in {
val reg = Register(obj, 5)
reg.obj mustEqual obj
reg.number mustEqual Some(5)
reg.name mustEqual None
reg.callback mustEqual None
reg.number.contains(5) mustEqual true
reg.name.isEmpty mustEqual true
reg.callback.isEmpty mustEqual true
}
"construct (object, suggested number, callback)" in {
val reg = Register(obj, 5, Actor.noSender)
reg.obj mustEqual obj
reg.number mustEqual Some(5)
reg.name mustEqual None
reg.callback mustEqual Some(Actor.noSender)
reg.number.contains(5) mustEqual true
reg.name.isEmpty mustEqual true
reg.callback.contains(Actor.noSender) mustEqual true
}
"construct (object, pool name)" in {
val reg = Register(obj, "pool")
reg.obj mustEqual obj
reg.number mustEqual None
reg.name mustEqual Some("pool")
reg.callback mustEqual None
reg.number.isEmpty mustEqual true
reg.name.contains("pool") mustEqual true
reg.callback.isEmpty mustEqual true
}
"construct (object, pool name, callback)" in {
val reg = Register(obj, "pool", Actor.noSender)
reg.obj mustEqual obj
reg.number mustEqual None
reg.name mustEqual Some("pool")
reg.callback mustEqual Some(Actor.noSender)
reg.number.isEmpty mustEqual true
reg.name.contains("pool") mustEqual true
reg.callback.contains(Actor.noSender) mustEqual true
}
}
}

View file

@ -341,7 +341,7 @@ object UniqueNumberSystemTest {
* @see `UniqueNumberSystem.AllocateNumberPoolActors(NumberPoolHub)(implicit ActorContext)`
*/
def AllocateNumberPoolActors(poolSource : NumberPoolHub)(implicit system : ActorSystem) : Map[String, ActorRef] = {
poolSource.Pools.map({ case ((pname, pool)) =>
poolSource.Pools.map({ case (pname, pool) =>
pname -> system.actorOf(Props(classOf[NumberPoolActor], pool), pname)
}).toMap
}

View file

@ -170,7 +170,6 @@ class WorldSessionActor extends Actor
var antChargingTick : Cancellable = DefaultCancellable.obj
var antDischargingTick : Cancellable = DefaultCancellable.obj
/**
* Convert a boolean value into an integer value.
* Use: `true:Int` or `false:Int`
@ -1131,7 +1130,7 @@ class WorldSessionActor extends Actor
log.warn(s"Vital target ${target.Definition.Name} damage resolution not supported using this method")
case ResponseToSelf(pkt) =>
log.info(s"Received a direct message: $pkt")
//log.info(s"Received a direct message: $pkt")
sendResponse(pkt)
case LoadedRemoteProjectile(projectile_guid, Some(projectile)) =>