- Introduce `ForceProcessingEnabled`, `InstallSuccessfulProcessingOverride`, and `EnqueueIncomingLine` helpers to streamline test setup. - Add new test suite `GenesisSmartReaderStopTests` to validate `Stop` behavior for different processing states. - Enhance `GenesisSmartReader` state management with a dedicated `Reset` method and improved `Stop` logic. - Improve buffer initialization in `ProcessOptoLine` to address null-value edge cases. - Update assembly version to `3.9.3043.1`.
153 lines
6.3 KiB
C#
153 lines
6.3 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
using TBF.Rig.RegisterReaders.GenesisRegReader;
|
|
using TBF.Rig.RegisterReaders.GenesisRegReader.common;
|
|
using TBF.Rig.RegisterReaders.GenesisRegReader.implementations;
|
|
|
|
namespace TBFTests.Rig.RegisterReaders.GenesisRegReader.implementations
|
|
{
|
|
[TestClass]
|
|
public class GenesisSmartReaderStopTests
|
|
{
|
|
private const int ChannelCount = 3;
|
|
|
|
private static GenesisCfg CreateCfg()
|
|
{
|
|
Factory factory = new Factory();
|
|
return new GenesisCfg(factory);
|
|
}
|
|
|
|
private static void SetPrivateField(object target, string fieldName, object value)
|
|
{
|
|
var field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
|
|
if (field == null)
|
|
throw new MissingFieldException(target.GetType().FullName, fieldName);
|
|
|
|
field.SetValue(target, value);
|
|
}
|
|
|
|
private static T GetPrivateField<T>(object target, string fieldName)
|
|
{
|
|
var field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
|
|
if (field == null)
|
|
throw new MissingFieldException(target.GetType().FullName, fieldName);
|
|
|
|
return (T)field.GetValue(target);
|
|
}
|
|
|
|
private static OptoTelegramRaw CreateOptoRecord(int channel, double volumeRawExt, double timestampExt)
|
|
{
|
|
return new OptoTelegramRaw
|
|
{
|
|
Flags = OptoTelegramFlags.OK,
|
|
VolumeRawExt = volumeRawExt,
|
|
TimestampExt = timestampExt,
|
|
iChannel = channel
|
|
};
|
|
}
|
|
|
|
private static void FillValidOptoDataForPostProcessing(GenesisSmartReader reader)
|
|
{
|
|
var optoData = GetPrivateField<OptoTelegramRaw[]>(reader, "optoData");
|
|
|
|
int idx = 0;
|
|
for (int group = 0; group < 6; group++)
|
|
{
|
|
optoData[idx++] = CreateOptoRecord(0, 10 + group, 100 + group);
|
|
optoData[idx++] = CreateOptoRecord(1, 20 + group, 100 + group);
|
|
optoData[idx++] = CreateOptoRecord(2, 30 + group, 100 + group);
|
|
}
|
|
|
|
SetPrivateField(reader, "optoDataCount", 18);
|
|
reader.TestStartTelegramIx = 1;
|
|
reader.TestEndTelegramIx = 17;
|
|
}
|
|
|
|
[TestMethod]
|
|
public void Stop_WhenStateIsCalculateStoredData_ShouldRunPostProcessing_AndFlushState()
|
|
{
|
|
var fake = new FakeSerialDriver();
|
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
|
|
|
reader.Initialize();
|
|
FillValidOptoDataForPostProcessing(reader);
|
|
|
|
SetPrivateField(reader, "dataStreamState", DataStreamState.CalculateStoredData);
|
|
SetPrivateField(reader, "startDataProcessing", false);
|
|
SetPrivateField(reader, "_stopQueueData", true);
|
|
|
|
fake.Open();
|
|
reader.optoSerialPort = fake;
|
|
|
|
reader.Stop();
|
|
|
|
var finalState = GetPrivateField<DataStreamState>(reader, "dataStreamState");
|
|
|
|
Assert.AreEqual(DataStreamState.Flush, finalState, "Stop() should finish in Flush state.");
|
|
Assert.IsFalse(fake.IsOpen, "Serial port should be closed by Stop().");
|
|
|
|
// These values are populated only if DataStreamPostProcessing() ran.
|
|
Assert.AreEqual((11.0 + 20.0 + 30.0) / 3.0, reader.VolumeLtrStartRaw, 1e-9,
|
|
"Expected post-processing to prepare raw start values.");
|
|
Assert.AreEqual((15.0 + 25.0 + 35.0) / 3.0, reader.VolumeLtrEndRaw, 1e-9,
|
|
"Expected post-processing to prepare raw end values.");
|
|
}
|
|
|
|
[TestMethod]
|
|
public void Stop_WhenStateIsProcessAndSave_ShouldNotRunPostProcessing_AndFlushState()
|
|
{
|
|
var fake = new FakeSerialDriver();
|
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
|
|
|
reader.Initialize();
|
|
FillValidOptoDataForPostProcessing(reader);
|
|
|
|
SetPrivateField(reader, "dataStreamState", DataStreamState.ProcessAndSave);
|
|
SetPrivateField(reader, "startDataProcessing", true);
|
|
SetPrivateField(reader, "_stopQueueData", false);
|
|
|
|
fake.Open();
|
|
reader.optoSerialPort = fake;
|
|
|
|
reader.Stop();
|
|
|
|
var finalState = GetPrivateField<DataStreamState>(reader, "dataStreamState");
|
|
var stopQueueData = GetPrivateField<bool>(reader, "_stopQueueData");
|
|
|
|
Assert.AreEqual(DataStreamState.Flush, finalState, "Stop() should finish in Flush state.");
|
|
Assert.IsTrue(stopQueueData, "Immediate stop path should stop queueing.");
|
|
Assert.IsFalse(fake.IsOpen, "Serial port should be closed by Stop().");
|
|
|
|
// Should still be default because DataStreamPostProcessing() must NOT run.
|
|
Assert.AreEqual(0.0, reader.VolumeLtrStartRaw, 1e-9,
|
|
"Post-processing should not run when previous state was ProcessAndSave.");
|
|
Assert.AreEqual(0.0, reader.VolumeLtrEndRaw, 1e-9,
|
|
"Post-processing should not run when previous state was ProcessAndSave.");
|
|
}
|
|
|
|
[TestMethod]
|
|
public void RequestImmediateStop_ShouldNotChangeCalculateStoredDataState()
|
|
{
|
|
var fake = new FakeSerialDriver();
|
|
var reader = new GenesisSmartReader(CreateCfg(), () => fake);
|
|
|
|
reader.Initialize();
|
|
|
|
SetPrivateField(reader, "dataStreamState", DataStreamState.CalculateStoredData);
|
|
SetPrivateField(reader, "startDataProcessing", true);
|
|
SetPrivateField(reader, "_stopQueueData", false);
|
|
|
|
reader.RequestImmediateStop();
|
|
|
|
var state = GetPrivateField<DataStreamState>(reader, "dataStreamState");
|
|
var stopQueueData = GetPrivateField<bool>(reader, "_stopQueueData");
|
|
var startDataProcessing = GetPrivateField<bool>(reader, "startDataProcessing");
|
|
|
|
Assert.AreEqual(DataStreamState.CalculateStoredData, state,
|
|
"RequestImmediateStop() must not destroy CalculateStoredData state.");
|
|
Assert.IsTrue(stopQueueData, "Immediate stop should stop queueing.");
|
|
Assert.IsFalse(startDataProcessing, "Immediate stop should disable active processing.");
|
|
}
|
|
}
|
|
} |