void Check(bool value,string m){if(!value)throw new Exception(m);} foreach(var scenario in new[]{"normal","logout","destroy"}){ GContext.container=new Container();Addressables.Pending=new();Addressables.Released.Clear(); var subject=new Subject();var task=subject.Run();Check(!task.IsCompleted,"missing controlled load"); if(scenario=="logout")GContext.container.User.Lifetime.Cancel(); if(scenario=="destroy")subject.Destroyed=true; var asset=new GameObject();Addressables.Pending.SetResult(asset);await task; Check(subject.Applied==(scenario=="normal"),"stale map applied"); Check(Addressables.Released.Contains(asset)==(scenario!="normal"),"late asset ownership incorrect"); Console.WriteLine("PASS actual LoadMapByCurID resource boundary: "+scenario); } var ik=new IkSubject();ik.SetIKTarget(new Transform()); ik.RodBehaviour=new Rod();ik.SetIKTarget(new Transform()); var target=new Transform();ik.RodBehaviour.cCDIK=new IK();ik.SetIKTarget(target); Check(ReferenceEquals(ik.RodBehaviour.cCDIK.solver.target,target),"valid IK behavior changed"); Console.WriteLine("PASS actual SetIKTarget: no rod, no IK, normal target"); foreach(var scenario in new[]{"normal","cancelled-error","destroyed-error","stopped-error","active-error"}){ var stage=new StageSubject();var task=stage.Run(); if(scenario=="normal")stage.Gate.SetResult(true); else{ if(scenario=="cancelled-error")stage.Lifetime.Cancel(); if(scenario=="destroyed-error")stage.Destroyed=true; if(scenario=="stopped-error")stage.stopping=true; stage.Gate.SetException(new InvalidOperationException("released handle")); } if(scenario=="active-error"){ try{await task;throw new Exception("active startup error swallowed");}catch(InvalidOperationException){} }else await task; Check(stage.Completed==(scenario=="normal"),"wrong stage continuation"); Console.WriteLine("PASS actual FishingStage startup boundary: "+scenario); } public partial class Subject{ public bool Destroyed,Applied;public GameObject mapObjPrefab,_mapObj;public object fishingBehavior;public MapData _curMapData=new(); public void DestroyImmediate(GameObject go){} public static bool operator ==(Subject a,Subject b)=>ReferenceEquals(b,null)?ReferenceEquals(a,null)||a.Destroyed:ReferenceEquals(a,b); public static bool operator !=(Subject a,Subject b)=>!(a==b); public override bool Equals(object other)=>ReferenceEquals(this,other);public override int GetHashCode()=>base.GetHashCode(); } public class MapData{public string EnvName="test";} public class GameObject{public static implicit operator bool(GameObject value)=>value is not null;} public class Transform{} public static class GContext{public static Container container=new();} public class Container{public User User=new();public T Resolve()=>(T)(object)User;} public interface IUserService{CancellationToken LoginLifetime{get;}} public class User:IUserService{public CancellationTokenSource Lifetime=new();public CancellationToken LoginLifetime=>Lifetime.Token;} public static class Addressables{ public static TaskCompletionSource Pending;public static List Released=new(); public static Handle LoadAssetAsync(string path)=>new();public static void Release(GameObject value)=>Released.Add(value); } public class Handle{public Task Task=>Addressables.Pending.Task;} public partial class IkSubject{public Rod RodBehaviour;} public class Rod{public IK cCDIK;} public class IK{public Solver solver=new();public static implicit operator bool(IK value)=>value is not null;} public class Solver{public Transform target;} public class StageBase{public TaskCompletionSource Gate=new();public Task StartAsync()=>Gate.Task;} public partial class StageSubject{ public CancellationTokenSource Lifetime=new();public bool Completed,Destroyed,stopping; public static bool operator ==(StageSubject a,StageSubject b)=>ReferenceEquals(b,null)?ReferenceEquals(a,null)||a.Destroyed:ReferenceEquals(a,b); public static bool operator !=(StageSubject a,StageSubject b)=>!(a==b); public override bool Equals(object other)=>ReferenceEquals(this,other);public override int GetHashCode()=>base.GetHashCode(); } public static class Debug{public static void LogWarning(string message){}}