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; /// /// Gitea #642 guard: is a hand-maintained set; it must equal /// the drivers whose concrete types implement . Discovery is by reflection over the /// driver assemblies deployed beside this test; an assembly's driver type is the /// constant whose FIELD NAME equals the assembly suffix (Driver.Galaxy -> Galaxy = "GalaxyMxGateway"). /// 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(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}'"); } } }