using System;
using System.Linq;
using Sandbox.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame.Utilities;
using VRageMath;
using Xunit;
using P=AutoMiningScript.Program;
namespace AutoMiningScript.Tests
{
public class UnreachableSurveyTests
{
static P.TaskPlanner Planner() => new P.TaskPlanner(TestRig.Program());
static void Drain(P.TaskPlanner p) {for(int n=0;n<1024;n++)p.Advance();}
static P.TaskPlanner Survey(bool complete=true)
{
var p=Planner();p.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,250);
if(complete)Drain(p);return p;
}
static void Block(P.TaskPlanner p,P.Job j)
{
p.SetOwner(j,"miner-7");
p.Report(j,new P.JobReport {JobId=j.Id,Outcome="Blocked",EntryUnreachable=true,Message="machine flag, not a localized reason"});
}
[Fact]
public void FlagRoundTripsAndLegacyMessagesAndJobsDefaultToFalse()
{
var p=Survey();var job=p.Jobs[0];job.EntryUnreachable=true;
var body=job.ToIni();Assert.True(P.Job.FromIni(body).EntryUnreachable);
body.Delete("job","EntryUnreachable");Assert.False(P.Job.FromIni(body).EntryUnreachable);
var report=new P.JobReport {JobId=job.Id,Outcome="Blocked",EntryUnreachable=true};
body=report.ToIni();Assert.True(P.JobReport.FromIni(body).EntryUnreachable);
body.Delete("result","EntryUnreachable");Assert.False(P.JobReport.FromIni(body).EntryUnreachable);
}
[Fact]
public void UnreachableEntrySkipsItsFortyTwoRaysWithoutClaimingAnyScan()
{
var p=Survey();var source=p.Jobs[0];Block(p,source);
// The dispatcher cannot select a sibling before the bounded summary runs.
Assert.Equal(-1,p.JobPriority(p.Jobs[1]));
Drain(p);Assert.Equal(252,p.PendingCount);Assert.Empty(p.OwnedJobs);
Assert.All(p.Jobs.Where(j=>j.Entry==source.Entry),j=>{Assert.Equal("Blocked",j.Outcome);Assert.Null(j.Scan);});
Assert.All(p.Jobs.Where(j=>j.Entry!=source.Entry),j=>Assert.False(P.TaskPlanner.Finished(j)));
p.Report(source,new P.JobReport {Outcome="Blocked",EntryUnreachable=true});Drain(p);
Assert.Equal(252,p.PendingCount);
}
[Fact]
public void OrdinaryRayOrCameraFailureDoesNotBlockOtherDirections()
{
var p=Survey();var source=p.Jobs[0];
p.Report(source,new P.JobReport {Outcome="Blocked",Message=P.L.MinerSurveyEntryStalled});Drain(p);
Assert.Equal(293,p.PendingCount);Assert.False(source.EntryUnreachable);
Assert.Equal(0,p.JobPriority(p.Jobs[1]));Assert.False(P.TaskPlanner.Finished(p.Jobs[1]));
}
[Fact]
public void OtherOwnerCanStillDiscoverAndDrillAtTheBlockedObservation()
{
var p=Survey();var source=p.Jobs[0];var active=p.Jobs[1];p.SetOwner(active,"miner-2");
Block(p,source);Drain(p);Assert.Equal(active,p.OwnedJobs["miner-2"]);
Assert.False(P.TaskPlanner.Finished(active));Assert.Equal(253,p.PendingCount);
// A real surface report remains useful even if another miner could not approach.
p.Report(active,new P.JobReport {Outcome="SurveyHit",EntryUnreachable=true,Position=active.Entry+Vector3D.Forward*10,Direction=Vector3D.Forward,Up=Vector3D.Up,EntityId=42});
Drain(p);Assert.Equal("SurveyHit",active.Outcome);Assert.False(active.EntryUnreachable);
var holes=p.Jobs.Where(j=>j.Kind==P.JobKind.Probe).ToList();Assert.Equal(145,holes.Count);
Assert.All(holes,j=>{Assert.True(p.JobPriority(j)>0);Assert.False(P.TaskPlanner.Finished(j));});
Assert.Equal(252+holes.Count,p.PendingCount);Assert.Empty(p.OwnedJobs);
}
[Fact]
public void SameCoordinatesInAnotherRegionAndNearbyEntriesRemainAvailable()
{
var p=Survey();var source=p.Jobs[0];var nearby=p.Jobs[1];nearby.Entry+=Vector3D.Right*.001;
p.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,250);Drain(p);
p.Manual(source.Entry,Vector3D.Forward,Vector3D.Up,6,6,10);Drain(p);
Block(p,source);Drain(p);
Assert.False(P.TaskPlanner.Finished(nearby));Assert.Equal(0,p.JobPriority(nearby));
Assert.All(p.Jobs.Where(j=>j.RegionId!=source.RegionId),j=>Assert.False(P.TaskPlanner.Finished(j)));
}
[Fact]
public void EarlyBlockSurvivesReloadAndAlsoSkipsRaysGeneratedLater()
{
var p=Survey(false);Assert.InRange(p.Jobs.Count,1,8);var source=p.Jobs[0];Block(p,source);
var save=new MyIni();p.Save(save);var restored=Planner();restored.Load(save);
Drain(restored);Assert.Equal(294,restored.Jobs.Count);Assert.Equal(252,restored.PendingCount);
Assert.True(restored.Find(source.Id).EntryUnreachable);
Assert.All(restored.Jobs.Where(j=>j.Entry==source.Entry),j=>{Assert.Equal("Blocked",j.Outcome);Assert.Null(j.Scan);});
}
[Fact]
public void CheckpointAlreadyInProgressRecordsSkippedSiblingsAndSourceFlag()
{
var p=Survey();var save=new MyIni();Assert.False(p.Checkpoint(save));
Block(p,p.Jobs[0]);Drain(p);bool complete=false;
for(int n=0;n<1024&&!complete;n++)complete=p.Checkpoint(save);
Assert.True(complete);var restored=Planner();restored.Load(save);Drain(restored);
Assert.Equal(252,restored.PendingCount);Assert.True(restored.Jobs[0].EntryUnreachable);
Assert.All(restored.Jobs.Take(42),j=>Assert.Equal("Blocked",j.Outcome));
}
[Fact]
public void WholeBlockedSearchIsIncompleteAndNeverCreatesCoverage()
{
var p=Survey();foreach(var group in p.Jobs.GroupBy(j=>j.Entry))Block(p,group.First());
Drain(p);Assert.Equal(0,p.PendingCount);Assert.Equal("Sampling incomplete: blocked observations",p.Regions[0].Status);
Assert.All(p.Jobs,j=>{Assert.Equal("Blocked",j.Outcome);Assert.Null(j.Scan);});
p.ClearTasks();p.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,250);Drain(p);
Assert.Equal(294,p.PendingCount);Assert.All(p.Jobs,j=>Assert.Equal(0,p.JobPriority(j)));
}
[Fact]
public void OccupiedSiblingIsSkippedOnlyAfterItsOwnerReleasesIt()
{
var p=Survey();var active=p.Jobs[1];p.SetOwner(active,"miner-2");Block(p,p.Jobs[0]);Drain(p);
Assert.Equal(253,p.PendingCount);p.SetOwner(active,"");
Assert.Equal(-1,p.JobPriority(active));Assert.Equal(252,p.PendingCount);Assert.Empty(p.OwnedJobs);
}
[Fact]
public void SkippingYieldsToBudgetButAssignmentStillCannotTakeBlockedEntry()
{
var program=TestRig.Program();var runtime=new Stub<IMyGridProgramRuntimeInfo>().Set("MaxInstructionCount",50000).Set("CurrentInstructionCount",0);
TestRig.SetBase(program,"Runtime",runtime.Value);var p=new P.TaskPlanner(program);
p.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,250);Drain(p);Block(p,p.Jobs[0]);
runtime.Set("CurrentInstructionCount",30000);p.Advance();Assert.Equal(293,p.PendingCount);
runtime.Set("CurrentInstructionCount",0);Assert.Equal(-1,p.JobPriority(p.Jobs[1]));Drain(p);Assert.Equal(252,p.PendingCount);
}
}
}
using System;
using System.Linq;
using Sandbox.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame.Utilities;
using VRageMath;
using Xunit;
using P=AutoMiningScript.Program;
namespace AutoMiningScript.Tests
{
public class UnreachableSurveyTests
{
static P.TaskPlanner Planner() => new P.TaskPlanner(TestRig.Program());
static void Drain(P.TaskPlanner p) {for(int n=0;n<1024;n++)p.Advance();}
static P.TaskPlanner Survey(bool complete=true)
{
var p=Planner();p.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,250);
if(complete)Drain(p);return p;
}
static void Block(P.TaskPlanner p,P.Job j)
{
p.SetOwner(j,"miner-7");
p.Report(j,new P.JobReport {JobId=j.Id,Outcome="Blocked",EntryUnreachable=true,Message="machine flag, not a localized reason"});
}
[Fact]
public void FlagRoundTripsAndLegacyMessagesAndJobsDefaultToFalse()
{
var p=Survey();var job=p.Jobs[0];job.EntryUnreachable=true;
var body=job.ToIni();Assert.True(P.Job.FromIni(body).EntryUnreachable);
body.Delete("job","EntryUnreachable");Assert.False(P.Job.FromIni(body).EntryUnreachable);
var report=new P.JobReport {JobId=job.Id,Outcome="Blocked",EntryUnreachable=true};
body=report.ToIni();Assert.True(P.JobReport.FromIni(body).EntryUnreachable);
body.Delete("result","EntryUnreachable");Assert.False(P.JobReport.FromIni(body).EntryUnreachable);
}
[Fact]
public void UnreachableEntrySkipsItsFortyTwoRaysWithoutClaimingAnyScan()
{
var p=Survey();var source=p.Jobs[0];Block(p,source);
// The dispatcher cannot select a sibling before the bounded summary runs.
Assert.Equal(-1,p.JobPriority(p.Jobs[1]));
Drain(p);Assert.Equal(252,p.PendingCount);Assert.Empty(p.OwnedJobs);
Assert.All(p.Jobs.Where(j=>j.Entry==source.Entry),j=>{Assert.Equal("Blocked",j.Outcome);Assert.Null(j.Scan);});
Assert.All(p.Jobs.Where(j=>j.Entry!=source.Entry),j=>Assert.False(P.TaskPlanner.Finished(j)));
p.Report(source,new P.JobReport {Outcome="Blocked",EntryUnreachable=true});Drain(p);
Assert.Equal(252,p.PendingCount);
}
[Fact]
public void OrdinaryRayOrCameraFailureDoesNotBlockOtherDirections()
{
var p=Survey();var source=p.Jobs[0];
p.Report(source,new P.JobReport {Outcome="Blocked",Message=P.L.MinerSurveyEntryStalled});Drain(p);
Assert.Equal(293,p.PendingCount);Assert.False(source.EntryUnreachable);
Assert.Equal(0,p.JobPriority(p.Jobs[1]));Assert.False(P.TaskPlanner.Finished(p.Jobs[1]));
}
[Fact]
public void OtherOwnerCanStillDiscoverAndDrillAtTheBlockedObservation()
{
var p=Survey();var source=p.Jobs[0];var active=p.Jobs[1];p.SetOwner(active,"miner-2");
Block(p,source);Drain(p);Assert.Equal(active,p.OwnedJobs["miner-2"]);
Assert.False(P.TaskPlanner.Finished(active));Assert.Equal(253,p.PendingCount);
// A real surface report remains useful even if another miner could not approach.
p.Report(active,new P.JobReport {Outcome="SurveyHit",EntryUnreachable=true,Position=active.Entry+Vector3D.Forward*10,Direction=Vector3D.Forward,Up=Vector3D.Up,EntityId=42});
Drain(p);Assert.Equal("SurveyHit",active.Outcome);Assert.False(active.EntryUnreachable);
var holes=p.Jobs.Where(j=>j.Kind==P.JobKind.Probe).ToList();Assert.Equal(145,holes.Count);
Assert.All(holes,j=>{Assert.True(p.JobPriority(j)>0);Assert.False(P.TaskPlanner.Finished(j));});
Assert.Equal(252+holes.Count,p.PendingCount);Assert.Empty(p.OwnedJobs);
}
[Fact]
public void SameCoordinatesInAnotherRegionAndNearbyEntriesRemainAvailable()
{
var p=Survey();var source=p.Jobs[0];var nearby=p.Jobs[1];nearby.Entry+=Vector3D.Right*.001;
p.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,250);Drain(p);
p.Manual(source.Entry,Vector3D.Forward,Vector3D.Up,6,6,10);Drain(p);
Block(p,source);Drain(p);
Assert.False(P.TaskPlanner.Finished(nearby));Assert.Equal(0,p.JobPriority(nearby));
Assert.All(p.Jobs.Where(j=>j.RegionId!=source.RegionId),j=>Assert.False(P.TaskPlanner.Finished(j)));
}
[Fact]
public void EarlyBlockSurvivesReloadAndAlsoSkipsRaysGeneratedLater()
{
var p=Survey(false);Assert.InRange(p.Jobs.Count,1,8);var source=p.Jobs[0];Block(p,source);
var save=new MyIni();p.Save(save);var restored=Planner();restored.Load(save);
Drain(restored);Assert.Equal(294,restored.Jobs.Count);Assert.Equal(252,restored.PendingCount);
Assert.True(restored.Find(source.Id).EntryUnreachable);
Assert.All(restored.Jobs.Where(j=>j.Entry==source.Entry),j=>{Assert.Equal("Blocked",j.Outcome);Assert.Null(j.Scan);});
}
[Fact]
public void CheckpointAlreadyInProgressRecordsSkippedSiblingsAndSourceFlag()
{
var p=Survey();var save=new MyIni();Assert.False(p.Checkpoint(save));
Block(p,p.Jobs[0]);Drain(p);bool complete=false;
for(int n=0;n<1024&&!complete;n++)complete=p.Checkpoint(save);
Assert.True(complete);var restored=Planner();restored.Load(save);Drain(restored);
Assert.Equal(252,restored.PendingCount);Assert.True(restored.Jobs[0].EntryUnreachable);
Assert.All(restored.Jobs.Take(42),j=>Assert.Equal("Blocked",j.Outcome));
}
[Fact]
public void WholeBlockedSearchIsIncompleteAndNeverCreatesCoverage()
{
var p=Survey();foreach(var group in p.Jobs.GroupBy(j=>j.Entry))Block(p,group.First());
Drain(p);Assert.Equal(0,p.PendingCount);Assert.Equal("Sampling incomplete: blocked observations",p.Regions[0].Status);
Assert.All(p.Jobs,j=>{Assert.Equal("Blocked",j.Outcome);Assert.Null(j.Scan);});
p.ClearTasks();p.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,250);Drain(p);
Assert.Equal(294,p.PendingCount);Assert.All(p.Jobs,j=>Assert.Equal(0,p.JobPriority(j)));
}
[Fact]
public void OccupiedSiblingIsSkippedOnlyAfterItsOwnerReleasesIt()
{
var p=Survey();var active=p.Jobs[1];p.SetOwner(active,"miner-2");Block(p,p.Jobs[0]);Drain(p);
Assert.Equal(253,p.PendingCount);p.SetOwner(active,"");
Assert.Equal(-1,p.JobPriority(active));Assert.Equal(252,p.PendingCount);Assert.Empty(p.OwnedJobs);
}
[Fact]
public void SkippingYieldsToBudgetButAssignmentStillCannotTakeBlockedEntry()
{
var program=TestRig.Program();var runtime=new Stub<IMyGridProgramRuntimeInfo>().Set("MaxInstructionCount",50000).Set("CurrentInstructionCount",0);
TestRig.SetBase(program,"Runtime",runtime.Value);var p=new P.TaskPlanner(program);
p.Survey(Vector3D.Zero,Vector3D.Zero,Vector3D.Forward,Vector3D.Up,250);Drain(p);Block(p,p.Jobs[0]);
runtime.Set("CurrentInstructionCount",30000);p.Advance();Assert.Equal(293,p.PendingCount);
runtime.Set("CurrentInstructionCount",0);Assert.Equal(-1,p.JobPriority(p.Jobs[1]));Drain(p);Assert.Equal(252,p.PendingCount);
}
}
}