feat(infra): add TagMapper with address mapping, value parsing, and quality mapping
This commit is contained in:
43
infra/lmxfakeproxy/TagMapper.cs
Normal file
43
infra/lmxfakeproxy/TagMapper.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using LmxFakeProxy.Grpc;
|
||||||
|
|
||||||
|
namespace LmxFakeProxy;
|
||||||
|
|
||||||
|
public class TagMapper
|
||||||
|
{
|
||||||
|
private readonly string _prefix;
|
||||||
|
|
||||||
|
public TagMapper(string prefix)
|
||||||
|
{
|
||||||
|
_prefix = prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToOpcNodeId(string lmxTag) => $"{_prefix}{lmxTag}";
|
||||||
|
|
||||||
|
public static object ParseWriteValue(string value)
|
||||||
|
{
|
||||||
|
if (double.TryParse(value, System.Globalization.NumberStyles.Float,
|
||||||
|
System.Globalization.CultureInfo.InvariantCulture, out var d))
|
||||||
|
return d;
|
||||||
|
if (bool.TryParse(value, out var b))
|
||||||
|
return b;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string MapQuality(uint statusCode)
|
||||||
|
{
|
||||||
|
if (statusCode == 0) return "Good";
|
||||||
|
if ((statusCode & 0x80000000) != 0) return "Bad";
|
||||||
|
return "Uncertain";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VtqMessage ToVtqMessage(string tag, object? value, DateTime timestampUtc, uint statusCode)
|
||||||
|
{
|
||||||
|
return new VtqMessage
|
||||||
|
{
|
||||||
|
Tag = tag,
|
||||||
|
Value = value?.ToString() ?? string.Empty,
|
||||||
|
TimestampUtcTicks = timestampUtc.Ticks,
|
||||||
|
Quality = MapQuality(statusCode)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace LmxFakeProxy.Tests;
|
||||||
|
|
||||||
|
public class TagMappingTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ToOpcNodeId_PrependsPrefix()
|
||||||
|
{
|
||||||
|
var mapper = new TagMapper("ns=3;s=");
|
||||||
|
Assert.Equal("ns=3;s=Motor.Speed", mapper.ToOpcNodeId("Motor.Speed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToOpcNodeId_CustomPrefix()
|
||||||
|
{
|
||||||
|
var mapper = new TagMapper("ns=2;s=MyFolder.");
|
||||||
|
Assert.Equal("ns=2;s=MyFolder.Pump.Pressure", mapper.ToOpcNodeId("Pump.Pressure"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToOpcNodeId_EmptyPrefix_PassesThrough()
|
||||||
|
{
|
||||||
|
var mapper = new TagMapper("");
|
||||||
|
Assert.Equal("Motor.Speed", mapper.ToOpcNodeId("Motor.Speed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseWriteValue_Double()
|
||||||
|
{
|
||||||
|
Assert.Equal(42.5, TagMapper.ParseWriteValue("42.5"));
|
||||||
|
Assert.IsType<double>(TagMapper.ParseWriteValue("42.5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseWriteValue_Bool()
|
||||||
|
{
|
||||||
|
Assert.Equal(true, TagMapper.ParseWriteValue("true"));
|
||||||
|
Assert.Equal(false, TagMapper.ParseWriteValue("False"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseWriteValue_Uint()
|
||||||
|
{
|
||||||
|
// "100" parses as double first (double.TryParse succeeds for integers)
|
||||||
|
var result = TagMapper.ParseWriteValue("100");
|
||||||
|
Assert.IsType<double>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseWriteValue_FallsBackToString()
|
||||||
|
{
|
||||||
|
Assert.Equal("hello", TagMapper.ParseWriteValue("hello"));
|
||||||
|
Assert.IsType<string>(TagMapper.ParseWriteValue("hello"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MapStatusCode_Good()
|
||||||
|
{
|
||||||
|
Assert.Equal("Good", TagMapper.MapQuality(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MapStatusCode_Bad()
|
||||||
|
{
|
||||||
|
Assert.Equal("Bad", TagMapper.MapQuality(0x80000000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MapStatusCode_Uncertain()
|
||||||
|
{
|
||||||
|
Assert.Equal("Uncertain", TagMapper.MapQuality(0x40000000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToVtqMessage_ConvertsCorrectly()
|
||||||
|
{
|
||||||
|
var vtq = TagMapper.ToVtqMessage("Motor.Speed", 42.5, DateTime.UtcNow, 0);
|
||||||
|
Assert.Equal("Motor.Speed", vtq.Tag);
|
||||||
|
Assert.Equal("42.5", vtq.Value);
|
||||||
|
Assert.Equal("Good", vtq.Quality);
|
||||||
|
Assert.True(vtq.TimestampUtcTicks > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user