62f19dd013
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
54 lines
2.7 KiB
C#
54 lines
2.7 KiB
C#
using System.Reflection;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors;
|
|
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;
|
|
|
|
/// <summary>
|
|
/// Gitea #642 guard: <see cref="NativeAlarmModel.SupportsNativeAlarms"/> is a hand-maintained set; it must equal
|
|
/// the drivers whose concrete types implement <see cref="IAlarmSource"/>. Discovery is by reflection over the
|
|
/// driver assemblies deployed beside this test; an assembly's driver type is the <see cref="DriverTypeNames"/>
|
|
/// constant whose FIELD NAME equals the assembly suffix (Driver.Galaxy -> Galaxy = "GalaxyMxGateway").
|
|
/// </summary>
|
|
public sealed class NativeAlarmDriverSetGuardTests
|
|
{
|
|
private static readonly string[] NonDriverSuffixes = [".Contracts", ".Addressing", ".Cli", ".Historian.Gateway"];
|
|
|
|
[Fact]
|
|
public void SupportsNativeAlarms_matches_the_drivers_implementing_IAlarmSource()
|
|
{
|
|
var binDir = Path.GetDirectoryName(typeof(NativeAlarmDriverSetGuardTests).Assembly.Location)!;
|
|
var constants = typeof(DriverTypeNames).GetFields(BindingFlags.Public | BindingFlags.Static)
|
|
.Where(f => f.IsLiteral && f.FieldType == typeof(string))
|
|
.ToDictionary(f => f.Name, f => (string)f.GetRawConstantValue()!, StringComparer.OrdinalIgnoreCase);
|
|
|
|
const string prefix = "ZB.MOM.WW.OtOpcUa.Driver.";
|
|
var implementers = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
var scanned = 0;
|
|
foreach (var dll in Directory.GetFiles(binDir, prefix + "*.dll"))
|
|
{
|
|
var name = Path.GetFileNameWithoutExtension(dll);
|
|
if (NonDriverSuffixes.Any(s => name.EndsWith(s, StringComparison.Ordinal))) { continue; }
|
|
Type[] types;
|
|
try { types = Assembly.LoadFrom(dll).GetTypes(); }
|
|
catch (ReflectionTypeLoadException ex) { types = ex.Types.Where(t => t is not null).ToArray()!; }
|
|
scanned++;
|
|
if (!types.Any(t => t.IsClass && !t.IsAbstract && typeof(IAlarmSource).IsAssignableFrom(t))) { continue; }
|
|
var suffix = name[prefix.Length..];
|
|
constants.TryGetValue(suffix, out var typeName).ShouldBeTrue($"no DriverTypeNames constant named '{suffix}' for {name}");
|
|
implementers.Add(typeName!);
|
|
}
|
|
|
|
scanned.ShouldBeGreaterThan(5, "driver assemblies were not deployed to the test output; the guard would be vacuous");
|
|
implementers.Count.ShouldBeGreaterThan(0);
|
|
|
|
foreach (var typeName in constants.Values)
|
|
{
|
|
NativeAlarmModel.SupportsNativeAlarms(typeName).ShouldBe(implementers.Contains(typeName),
|
|
$"NativeAlarmModel.AlarmDriverTypes disagrees with IAlarmSource for driver type '{typeName}'");
|
|
}
|
|
}
|
|
}
|