Files
lmxopcua/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/NativeAlarmDriverSetGuardTests.cs
T

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}'");
}
}
}