Merge #613 slice: MTConnect authoring-time DataType advisory + ignored-DeviceName warning
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -117,6 +117,37 @@ public sealed class MTConnectRawTagBindingTests
|
||||
return (driver, agent);
|
||||
}
|
||||
|
||||
private static RawTagEntry OnDevice(string rawPath, string dataItemId, string device) =>
|
||||
Entry(rawPath, dataItemId) with { DeviceName = device };
|
||||
|
||||
private static async Task<List<string>> InitWarningsAsync(params RawTagEntry[] rawTags)
|
||||
{
|
||||
var logger = new RecordingDriverLogger();
|
||||
var driver = new MTConnectDriver(Bare(), "mt1", _ => CannedAgentClient.FromFixtures(), logger);
|
||||
await driver.InitializeAsync(MergedConfig(rawTags), Ct);
|
||||
await driver.ShutdownAsync(Ct);
|
||||
|
||||
return [.. logger.Warnings];
|
||||
}
|
||||
|
||||
/// <summary>#613: differing RawTagEntry.DeviceName values are ignored for routing, so init says so.</summary>
|
||||
[Fact]
|
||||
public async Task Differing_raw_device_names_log_an_ignored_routing_warning()
|
||||
{
|
||||
// Positive control: a single /raw Device is the ordinary case and must stay silent.
|
||||
(await InitWarningsAsync(
|
||||
OnDevice(PositionRawPath, PositionDataItemId, "cncA"),
|
||||
OnDevice(ExecutionRawPath, ExecutionDataItemId, "cncA")))
|
||||
.ShouldNotContain(w => w.Contains("RawTagEntry.DeviceName"));
|
||||
|
||||
var warnings = await InitWarningsAsync(
|
||||
OnDevice(PositionRawPath, PositionDataItemId, "cncA"),
|
||||
OnDevice(ExecutionRawPath, ExecutionDataItemId, "cncB"));
|
||||
|
||||
var w = warnings.Where(x => x.Contains("RawTagEntry.DeviceName")).ShouldHaveSingleItem();
|
||||
w.ShouldContain("cncA, cncB");
|
||||
}
|
||||
|
||||
// ---- the production data plane: subscribe by RawPath, publish by RawPath ----
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -295,4 +295,37 @@ public sealed class MTConnectTagConfigModelTests
|
||||
[InlineData("""{"fullName":"x","driverDataType":8,"dataType":"Int32"}""")]
|
||||
public void Validate_rejects_a_driverDataType_written_as_an_unquoted_number(string json)
|
||||
=> MTConnectTagConfigModel.FromJson(json).Validate().ShouldNotBeNull().ShouldContain("8");
|
||||
|
||||
private static MTConnectTagConfigModel Stamped(string category, string type, string dataType)
|
||||
=> MTConnectTagConfigModel.FromJson(
|
||||
$"{{\"fullName\":\"x\",\"dataType\":\"{dataType}\",\"mtCategory\":\"{category}\",\"mtType\":\"{type}\"}}");
|
||||
|
||||
[Theory]
|
||||
[InlineData("SAMPLE", "POSITION", "Boolean")] // numeric inferred, non-numeric declared
|
||||
[InlineData("SAMPLE", "POSITION", "Int32")] // fractional readings cannot fit
|
||||
[InlineData("EVENT", "EXECUTION", "Float64")] // text inferred, numeric declared
|
||||
[InlineData("CONDITION", "TEMPERATURE", "Int32")]
|
||||
public void Warnings_flags_a_declared_type_that_cannot_hold_the_inferred_one_without_blocking(
|
||||
string category, string type, string dataType)
|
||||
{
|
||||
var m = Stamped(category, type, dataType);
|
||||
|
||||
m.Warnings().ShouldHaveSingleItem().ShouldContain(dataType);
|
||||
m.Validate().ShouldBeNull(); // advisory: never blocks
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("SAMPLE", "POSITION", "Float64")]
|
||||
[InlineData("SAMPLE", "POSITION", "String")] // text holds anything
|
||||
[InlineData("EVENT", "EXECUTION", "String")]
|
||||
[InlineData("EVENT", "PART_COUNT", "Int64")]
|
||||
[InlineData("EVENT", "PART_COUNT", "Float64")]
|
||||
public void Warnings_is_quiet_when_the_declared_type_holds_the_inferred_one(
|
||||
string category, string type, string dataType)
|
||||
=> Stamped(category, type, dataType).Warnings().ShouldBeEmpty();
|
||||
|
||||
[Fact]
|
||||
public void Warnings_is_a_noop_without_probe_metadata()
|
||||
=> MTConnectTagConfigModel.FromJson("{\"fullName\":\"x\",\"dataType\":\"Boolean\"}")
|
||||
.Warnings().ShouldBeEmpty();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user