XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

AutoMiningScript

【SpaceEngineer】全自动挖矿脚本

公开
关注 0 Fork 0 Star 0
UTF-8
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame.Utilities;
using Xunit;
using P=AutoMiningScript.Program;

namespace AutoMiningScript.Tests
{
    public class WireRebindTests
    {
        sealed class Delivery { public P.Packet Packet; public long Address; }
        sealed class Rig
        {
            public readonly P Program=TestRig.Program();
            public readonly Queue<MyIGCMessage> Incoming=new Queue<MyIGCMessage>();
            public readonly List<Delivery> Sent=new List<Delivery>();
            public readonly List<P.Packet> Received=new List<P.Packet>();
            public Rig()
            {
                Program.Config=new P.Settings("[System]\nId=base\nFleetId=mining\nBaseId=base","fleet","base");
                var broadcast=new Stub<IMyBroadcastListener>();
                var unicast=new Stub<IMyUnicastListener>().Method("get_HasPendingMessage",a=>Incoming.Count>0).Method("AcceptMessage",a=>Incoming.Dequeue());
                var igc=new Stub<IMyIntergridCommunicationSystem>().Set("UnicastListener",unicast.Value)
                    .Method("RegisterBroadcastListener",a=>broadcast.Value)
                    .Method("SendBroadcastMessage",a=>Capture(0,(string)a[1]))
                    .Method("SendUnicastMessage",a=>{Capture((long)a[0],(string)a[2]);return true;});
                TestRig.SetBase(Program,"IGC",igc.Value);Program.Bus=new P.Wire(Program);
                Add("old",1);Drain();
            }
            object Capture(long address,string value)
            {
                P.Packet packet;Assert.True(P.Packet.TryDecode(value,"mining",out packet));Sent.Add(new Delivery {Address=address,Packet=packet});return null;
            }
            public void Add(string session,long sequence,long address=123,string kind="HELLO",bool reliable=false,long epoch=0,MyIni body=null)
            {
                var packet=new P.Packet {From="miner-3",Target="base",Session=session,Seq=sequence,Id=session+"-"+kind+"-"+sequence,Kind=kind,Reliable=reliable,Epoch=epoch,Body=body??new MyIni()};
                Incoming.Enqueue(new MyIGCMessage(packet.Encode("mining"),"AMS2/mining",address));
            }
            public void Drain() {Program.Bus.Drain(p=>Received.Add(p));}
            public long SendAddress()
            {
                Program.Bus.Send("COMMAND","miner-3",new MyIni());return Sent.Last().Address;
            }
        }

        [Fact]
        public void RejectedReplacementKeepsTheOriginalAddressAndDoesNotAcknowledgeIt()
        {
            var r=new Rig();int decisions=0;r.Program.Bus.AllowRebind=p=>{decisions++;return false;};
            r.Add("new",1,456,reliable:true);r.Drain();
            Assert.Equal(1,decisions);Assert.Single(r.Received);Assert.Empty(r.Sent);Assert.Equal(123,r.SendAddress());
            r.Add("old",2);r.Drain();Assert.Equal(2,r.Received.Count);
        }

        [Fact]
        public void ApprovedReplacementMigratesProtectionDropsOldRetriesAndDeliversOnce()
        {
            var r=new Rig();r.Program.Bus.ProtectPeer("miner-3",123);
            r.Program.Bus.Send("JOB","miner-3",new MyIni(),true);
            r.Program.Bus.Send("JOB","unrelated",new MyIni(),true,789);
            int decisions=0;r.Program.Bus.AllowRebind=p=>{decisions++;return p.Source==456;};r.Sent.Clear();
            r.Add("new",1,456,reliable:true);r.Drain();
            Assert.Equal(1,decisions);Assert.Equal(2,r.Received.Count);Assert.Equal(456,r.Received.Last().Source);
            var ack=Assert.Single(r.Sent);Assert.Equal("ACK",ack.Packet.Kind);Assert.Equal(456,ack.Address);
            Assert.Equal(1,r.Program.Bus.PendingCount);Assert.Equal(456,r.SendAddress());
            r.Add("new",1,456,reliable:true);r.Drain();Assert.Equal(2,r.Received.Count);Assert.Equal(1,decisions);
            r.Sent.Clear();r.Program.Now=2;r.Program.Bus.Tick();
            var retry=Assert.Single(r.Sent);Assert.Equal(789,retry.Address);Assert.Equal("unrelated",retry.Packet.Target);
            // The new protected address works without another authorization callback.
            r.Program.Bus.AllowRebind=null;r.Add("new",2,456,kind:"TELEMETRY");r.Drain();Assert.Equal(3,r.Received.Count);
        }

        [Fact]
        public void RetiredSessionReplayCannotAskToMoveTheAddressBack()
        {
            var r=new Rig();int decisions=0;r.Program.Bus.AllowRebind=p=>{decisions++;return true;};
            r.Add("new",1,456);r.Drain();Assert.Equal(1,decisions);
            r.Add("old",999,123,reliable:true);r.Drain();
            Assert.Equal(1,decisions);Assert.Equal(2,r.Received.Count);Assert.Empty(r.Sent);Assert.Equal(456,r.SendAddress());
        }

        [Fact]
        public void CurrentSessionReplayAndWrongEpochNeverReachTheAuthorizationCallback()
        {
            var r=new Rig();int decisions=0;r.Program.Bus.AllowRebind=p=>{decisions++;return true;};
            r.Add("old",1,456,reliable:true);r.Add("new",1,456,reliable:true,epoch:1);r.Drain();
            Assert.Equal(0,decisions);Assert.Single(r.Received);Assert.Empty(r.Sent);Assert.Equal(123,r.SendAddress());
        }

        [Theory]
        [InlineData("ACK")]
        [InlineData("RESULT")]
        [InlineData("COMMAND")]
        public void NonRegistrationPacketsCannotAuthorizeAddressTakeover(string kind)
        {
            var r=new Rig();int decisions=0;r.Program.Bus.AllowRebind=p=>{decisions++;return true;};
            r.Add("new",1,456,kind,true);r.Drain();
            Assert.Equal(0,decisions);Assert.Single(r.Received);Assert.Empty(r.Sent);Assert.Equal(123,r.SendAddress());
        }

        [Theory]
        [InlineData("HELLO")]
        [InlineData("TELEMETRY")]
        [InlineData("DOCK_REQUEST")]
        [InlineData("DEPART_REQUEST")]
        public void OnlyAnExplicitApprovalAllowsFreshRegistrationKindsToRebind(string kind)
        {
            var r=new Rig();r.Program.Bus.AllowRebind=p=>p.Kind==kind&&p.Source==456;
            r.Add("new",1,456,kind);r.Drain();Assert.Equal(2,r.Received.Count);Assert.Equal(456,r.SendAddress());
        }

        [Fact]
        public void RejectedProtectedIdentityRemainsProtectedAfterItsAddressSlotWasForgotten()
        {
            var r=new Rig();r.Program.Bus.ProtectPeer("miner-3",123);r.Program.Bus.ForgetPeer("miner-3");
            int decisions=0;r.Program.Bus.AllowRebind=p=>{decisions++;return false;};
            r.Add("new",1,456,reliable:true);r.Drain();Assert.Equal(1,decisions);Assert.Single(r.Received);Assert.Empty(r.Sent);
            r.Add("old",2,123);r.Drain();Assert.Equal(2,r.Received.Count);Assert.Equal(123,r.SendAddress());
        }

        [Fact]
        public void InvalidAuthorizationPayloadCannotPartiallyCancelOrMoveTheBinding()
        {
            var r=new Rig();r.Program.Bus.Send("JOB","miner-3",new MyIni(),true);
            r.Program.Bus.AllowRebind=p=>{throw new ArgumentException("invalid replacement telemetry");};
            r.Add("new",1,456);r.Drain();
            Assert.Single(r.Received);Assert.Equal(1,r.Program.Bus.PendingCount);Assert.Equal(123,r.SendAddress());
        }
    }
}