tbf/TBFTests/Rig/TestMethods/iPerlCommunication/common/OptoTelegramRawTest.cs
Michal Buzik bcb33cde78 Store changes on Iperl
Add and expand unit tests for iPerl communication, refactor OptoHead methods, update log4net reference, and increment AssemblyVersion.
2026-03-03 14:34:30 +01:00

144 lines
4.6 KiB
C#

using System;
using JetBrains.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TBF.Rig.TestMethods.iPerlCommunication.common;
using TBF.Rig.TestMethods.iPerlCommunication.communication.C4.diagnosticLed.parserer;
namespace TBFTests.Rig.TestMethods.iPerlCommunication.common
{
[TestClass]
[TestSubject(typeof(OptoTelegramRaw))]
public class OptoTelegramRawTest
{
private const double EPS = 1e-6;
private static OptoTelegramRaw Create() => new OptoTelegramRaw();
private static DiagnosticLedState4Data CreateTelegram(uint rawVolume24, uint timestamp32)
{
string HexU(uint value, int bytes) => value.ToString($"X{bytes * 2}");
string[] fields =
{
"000000","0000","0000",
HexU(rawVolume24,3),"0000","0000",
HexU(timestamp32,4),"00","00000000",
"0000","0000","0000","0000","00"
};
return new DiagnosticLedState4Data("TEST", fields);
}
// helper: compute liters per tick exactly as production
private static double LitersPerTick =>
(4.0 / 1000.0) / 3.785411784 / 2.0;
private static double TimestampPerTick => 1.0 / 4096.0;
[TestMethod]
public void NormalProgression_NoWrap()
{
var sample = Create();
var d1 = CreateTelegram(1000, 2000);
double volLast = d1.RawVolume;
double tsLast = d1.AsicTimestamp;
var d2 = CreateTelegram(1010, 2010);
sample.UpdateFromSmart(d2, 0, 0, ref volLast, ref tsLast);
Assert.AreEqual(d2.RawVolume, sample.VolumeRawExt, EPS);
Assert.AreEqual(d2.AsicTimestamp, sample.TimestampExt, EPS);
}
[TestMethod]
public void VolumeForwardWrap_AddsOneFullVolumeRange()
{
var sample = Create();
var dLast = CreateTelegram((uint)((1 << 24) - 5), 0);
double volLast = dLast.RawVolume;
double tsLast = dLast.AsicTimestamp;
var dNew = CreateTelegram(3u, 0u);
sample.UpdateFromSmart(dNew, 0, 0, ref volLast, ref tsLast);
double expectedIncrease = (1 << 24) * LitersPerTick;
Assert.AreEqual(dNew.RawVolume + expectedIncrease, sample.VolumeRawExt, 1e-3);
}
[TestMethod]
public void TimestampForwardWrap_AddsOneFullTimeRange()
{
var sample = Create();
var dLast = CreateTelegram(0, (uint)((1UL << 32) - 10));
double volLast = dLast.RawVolume;
double tsLast = dLast.AsicTimestamp;
var dNew = CreateTelegram(0, 5);
sample.UpdateFromSmart(dNew, 0, 0, ref volLast, ref tsLast);
double expectedIncrease = (1UL << 32) * TimestampPerTick;
Assert.AreEqual(dNew.AsicTimestamp + expectedIncrease, sample.TimestampExt, 1e-3);
}
[TestMethod]
public void HugeJump_UsesFallback()
{
var sample = Create();
var dLast = CreateTelegram(1000, 1000);
double volLast = dLast.RawVolume;
double tsLast = dLast.AsicTimestamp;
var dNew = CreateTelegram((uint)(1 << 23), (uint)(1UL << 31));
sample.UpdateFromSmart(dNew, 0, 0, ref volLast, ref tsLast);
Assert.AreEqual(dNew.RawVolume, sample.VolumeRawExt, EPS);
Assert.AreEqual(dNew.AsicTimestamp, sample.TimestampExt, EPS);
}
[TestMethod]
public void LongRun_MultipleWraps_RemainsMonotonic()
{
var sample = new OptoTelegramRaw();
double volLast = double.NaN;
double tsLast = double.NaN;
uint volCounter = (uint)((1 << 24) - 100);
uint tsCounter = (uint)((1UL << 32) - 1000);
double prevVol = double.NegativeInfinity;
double prevTs = double.NegativeInfinity;
for (int i = 0; i < 500; i++)
{
unchecked
{
volCounter += 200_000u; // < 2^23
tsCounter += 50_000_000u; // < 2^31
}
var data = CreateTelegram(volCounter, tsCounter);
sample.UpdateFromSmart(data, 0, 0, ref volLast, ref tsLast);
Assert.IsTrue(sample.VolumeRawExt >= prevVol, $"Volume went backwards at i={i}");
Assert.IsTrue(sample.TimestampExt >= prevTs, $"Timestamp went backwards at i={i}");
prevVol = sample.VolumeRawExt;
prevTs = sample.TimestampExt;
}
}
}
}