using System.Reflection; using Shouldly; using Xunit; namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests; /// /// Asserts that Core.Abstractions stays a true contract project — it must not depend on /// any implementation type, any other OtOpcUa project, or anything beyond BCL + System types. /// Per docs/v2/plan.md decision #59 (Core.Abstractions internal-only for now; design as /// if public to minimize churn later). /// public sealed class InterfaceIndependenceTests { private static readonly Assembly Assembly = typeof(IDriver).Assembly; [Fact] public void Assembly_HasNoReferencesOutsideBcl() { // Allowed reference assembly name prefixes — BCL + the assembly itself. var allowed = new[] { "System", "Microsoft.Win32", "netstandard", "mscorlib", "ZB.MOM.WW.OtOpcUa.Core.Abstractions", }; var referenced = Assembly.GetReferencedAssemblies(); var disallowed = referenced .Where(r => !allowed.Any(a => r.Name!.StartsWith(a, StringComparison.Ordinal))) .ToList(); disallowed.ShouldBeEmpty( $"Core.Abstractions must reference only BCL/System assemblies. " + $"Found disallowed references: {string.Join(", ", disallowed.Select(a => a.Name))}"); } [Fact] public void AllPublicTypes_LiveInRootNamespace() { // Per the decision-#59 "design as if public" rule — no nested sub-namespaces; one flat surface. var publicTypes = Assembly.GetExportedTypes(); var nonRoot = publicTypes .Where(t => t.Namespace != "ZB.MOM.WW.OtOpcUa.Core.Abstractions") .ToList(); nonRoot.ShouldBeEmpty( $"Core.Abstractions should expose all public types in the root namespace. " + $"Found types in other namespaces: {string.Join(", ", nonRoot.Select(t => $"{t.FullName}"))}"); } [Theory] [InlineData(typeof(IDriver))] [InlineData(typeof(ITagDiscovery))] [InlineData(typeof(IReadable))] [InlineData(typeof(IWritable))] [InlineData(typeof(ISubscribable))] [InlineData(typeof(IAlarmSource))] [InlineData(typeof(IHistoryProvider))] [InlineData(typeof(IRediscoverable))] [InlineData(typeof(IHostConnectivityProbe))] [InlineData(typeof(IDriverConfigEditor))] [InlineData(typeof(IAddressSpaceBuilder))] public void EveryCapabilityInterface_IsPublic(Type type) { type.IsPublic.ShouldBeTrue($"{type.Name} must be public — drivers in separate assemblies implement it."); type.IsInterface.ShouldBeTrue($"{type.Name} must be an interface, not a class."); } }