diff --git a/adapter/MTConnect.NET-Applications-Adapter/Service.cs b/adapter/MTConnect.NET-Applications-Adapter/Service.cs
index 4d0ba2578..8596deac8 100644
--- a/adapter/MTConnect.NET-Applications-Adapter/Service.cs
+++ b/adapter/MTConnect.NET-Applications-Adapter/Service.cs
@@ -3,14 +3,18 @@
using MTConnect.Services;
using NLog;
+#if NET5_0_OR_GREATER
using System.Runtime.Versioning;
+#endif
namespace MTConnect.Applications
{
///
/// Class used to implement a Windows Service for an MTConnect Agent Application
///
+#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
+#endif
public class Service : MTConnectAdapterService
{
private static readonly Logger _serviceLogger = LogManager.GetLogger("service-logger");
diff --git a/agent/MTConnect.NET-Applications-Agents/Service.cs b/agent/MTConnect.NET-Applications-Agents/Service.cs
index 769780ce6..ce3b1925f 100644
--- a/agent/MTConnect.NET-Applications-Agents/Service.cs
+++ b/agent/MTConnect.NET-Applications-Agents/Service.cs
@@ -3,14 +3,18 @@
using MTConnect.Services;
using NLog;
+#if NET5_0_OR_GREATER
using System.Runtime.Versioning;
+#endif
namespace MTConnect.Applications
{
///
/// Class used to implement a Windows Service for an MTConnect Agent Application
///
+#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
+#endif
public class Service : MTConnectAgentService
{
private static readonly Logger _serviceLogger = LogManager.GetLogger("service-logger");
diff --git a/agent/Modules/MTConnect.NET-AgentModule-MqttRelay/Module.cs b/agent/Modules/MTConnect.NET-AgentModule-MqttRelay/Module.cs
index ab1673327..049dc784a 100644
--- a/agent/Modules/MTConnect.NET-AgentModule-MqttRelay/Module.cs
+++ b/agent/Modules/MTConnect.NET-AgentModule-MqttRelay/Module.cs
@@ -941,11 +941,17 @@ await AsyncVoidGuard.Run(
if (!conditionObservations.IsNullOrEmpty())
{
var multipleObservations = new List(conditionObservations.Count());
- foreach (var observation in conditionObservations)
+ // Rename to avoid CS0136: the
+ // enclosing AgentObservationAdded
+ // handler takes `observation` as its
+ // parameter; declaring an inner
+ // `observation` here shadows it and
+ // fails to compile under net4x.
+ foreach (var condObservation in conditionObservations)
{
- multipleObservations.Add(CloneAsObservation(observation));
+ multipleObservations.Add(CloneAsObservation(condObservation));
}
-
+
var result = await _entityServer.PublishObservations(_mqttClient, multipleObservations);
if (result != null && result.IsSuccess)
{
diff --git a/libraries/MTConnect.NET-HTTP/Ceen/Httpd/HttpServer.cs b/libraries/MTConnect.NET-HTTP/Ceen/Httpd/HttpServer.cs
index 66719fa21..25e821241 100644
--- a/libraries/MTConnect.NET-HTTP/Ceen/Httpd/HttpServer.cs
+++ b/libraries/MTConnect.NET-HTTP/Ceen/Httpd/HttpServer.cs
@@ -2,7 +2,9 @@
using System.Net;
using System.Linq;
using System.Net.Sockets;
+#if NET5_0_OR_GREATER
using System.Runtime.Versioning;
+#endif
using System.Threading.Tasks;
using System.Threading;
using System.Security.Cryptography.X509Certificates;
@@ -172,7 +174,9 @@ public void Setup(bool usessl, ServerConfig config)
/// The socket handle.
/// The remote endpoint.
/// The task ID to use.
+#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
+#endif
public void HandleRequest(SocketInformation socket, EndPoint remoteEndPoint, string logtaskid)
{
RunClient(socket, remoteEndPoint, logtaskid, Controller);
@@ -865,7 +869,9 @@ public static Task ListenAsync(
/// The remote endpoint.
/// The log task ID.
/// The controller instance
+#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
+#endif
private static void RunClient(SocketInformation socketinfo, EndPoint remoteEndPoint, string logtaskid, RunnerControl controller)
{
RunClient(new Socket(socketinfo), remoteEndPoint, logtaskid, controller);
diff --git a/libraries/MTConnect.NET-Services/MTConnectAdapterService.cs b/libraries/MTConnect.NET-Services/MTConnectAdapterService.cs
index 4e7b3fb85..5459864a2 100644
--- a/libraries/MTConnect.NET-Services/MTConnectAdapterService.cs
+++ b/libraries/MTConnect.NET-Services/MTConnectAdapterService.cs
@@ -5,7 +5,9 @@
using System.Diagnostics;
using System.IO;
using System.Reflection;
+#if NET5_0_OR_GREATER
using System.Runtime.Versioning;
+#endif
using System.ServiceProcess;
namespace MTConnect.Services
@@ -13,7 +15,9 @@ namespace MTConnect.Services
///
/// Class used to implement an MTConnect Adapter as a Windows Service
///
+#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
+#endif
public abstract class MTConnectAdapterService : ServiceBase
{
private const string DefaultServiceName = "MTConnect-Adapter";
diff --git a/libraries/MTConnect.NET-Services/MTConnectAgentService.cs b/libraries/MTConnect.NET-Services/MTConnectAgentService.cs
index a09843650..4134627f1 100644
--- a/libraries/MTConnect.NET-Services/MTConnectAgentService.cs
+++ b/libraries/MTConnect.NET-Services/MTConnectAgentService.cs
@@ -5,7 +5,9 @@
using System.Diagnostics;
using System.IO;
using System.Reflection;
+#if NET5_0_OR_GREATER
using System.Runtime.Versioning;
+#endif
using System.ServiceProcess;
namespace MTConnect.Services
@@ -13,7 +15,9 @@ namespace MTConnect.Services
///
/// Class used to implement an MTConnect Agent as a Windows Service
///
+#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
+#endif
public abstract class MTConnectAgentService : ServiceBase
{
private const string DefaultServiceName = "MTConnect.NET-Agent";
diff --git a/libraries/MTConnect.NET-Services/WindowsService.cs b/libraries/MTConnect.NET-Services/WindowsService.cs
index af5c441c6..cc43cf424 100644
--- a/libraries/MTConnect.NET-Services/WindowsService.cs
+++ b/libraries/MTConnect.NET-Services/WindowsService.cs
@@ -3,13 +3,17 @@
using System.Linq;
using System.Runtime.InteropServices;
+#if NET5_0_OR_GREATER
using System.Runtime.Versioning;
+#endif
using System.Security.Principal;
using System.ServiceProcess;
namespace MTConnect.Services
{
+#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
+#endif
internal static class WindowsService
{
public static bool ServiceExists(string serviceName)
diff --git a/libraries/MTConnect.NET-XML/MTConnect.NET-XML.csproj b/libraries/MTConnect.NET-XML/MTConnect.NET-XML.csproj
index 41e35537a..29a10bef2 100644
--- a/libraries/MTConnect.NET-XML/MTConnect.NET-XML.csproj
+++ b/libraries/MTConnect.NET-XML/MTConnect.NET-XML.csproj
@@ -17,7 +17,18 @@
MTConnect
Debug;Release;Package
-
+
+
+ 8.0
+
MTConnect.NET-XML implements the XML Document Format for use with the MTConnect.NET library. Supports MTConnect versions up to 2.7. Supports .NET Framework 4.6.1 up to .NET 9
README-Nuget.md
diff --git a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/ConditionObservationVariableScopeTests.cs b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/ConditionObservationVariableScopeTests.cs
new file mode 100644
index 000000000..752e96916
--- /dev/null
+++ b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/ConditionObservationVariableScopeTests.cs
@@ -0,0 +1,119 @@
+// Copyright (c) 2026 TrakHound Inc., All Rights Reserved.
+// TrakHound Inc. licenses this file to you under the MIT license.
+
+using System;
+using System.IO;
+using System.Linq;
+using NUnit.Framework;
+
+namespace MTConnect.AgentModule.MqttRelay.Tests
+{
+ // Pins the rename PR #194 lands on Module.cs to resolve the
+ // CS0136 shadowed-local diagnostic that fires under net4x. The
+ // original code in `AgentObservationAdded` declared an inner
+ // `var observation` inside a `foreach` loop that lived in the
+ // same scope as the handler's outer `observation` parameter:
+ //
+ // private async void AgentObservationAdded(object sender,
+ // IObservation observation) // <- outer name
+ // {
+ // ...
+ // foreach (var observation in conditionObservations) // <- shadow
+ // { ... }
+ // }
+ //
+ // The C# 5+ language spec section 7.6.2.1 forbids a local
+ // variable declaration from shadowing an enclosing
+ // parameter/local of the same name. The .NET 5+ compiler emits
+ // a warning that TreatWarningsAsErrors escalates to an error on
+ // net8.0, but the project's net4x roslyn pinned compiler emits
+ // CS0136 directly. PR #194 renames the inner declaration to
+ // `condObservation` (or similar non-shadowing name) so the
+ // multi-TFM build path stays green.
+ //
+ // This fixture reads the Module.cs source via reflection on the
+ // assembly's location and scans the relevant block, asserting
+ // that no `foreach (var observation` declaration remains inside
+ // the handler. A future contributor who re-introduces the
+ // shadow fails this test under net8.0 — the test TFM that the
+ // CI matrix exercises — instead of waiting for the next Release
+ // pack to surface the failure under net4x.
+ /// Pins the rename that resolves the net4x CS0136 shadow.
+ [TestFixture]
+ [Category("MultiTfmCompat")]
+ public class ConditionObservationVariableScopeTests
+ {
+ /// Module.cs AgentObservationAdded must not declare an inner `observation` loop variable.
+ [Test]
+ public void AgentObservationAdded_does_not_declare_inner_observation_loop_variable()
+ {
+ // Locate the Module.cs source by walking up from the test
+ // assembly to the repo root, then descending into the
+ // module's source tree. The path is stable in-tree;
+ // CI runs with the same layout.
+ var moduleSourcePath = FindModuleSourcePath();
+ Assert.That(moduleSourcePath, Is.Not.Null,
+ "Could not locate Module.cs for MTConnect.NET-AgentModule-MqttRelay.");
+
+ var source = File.ReadAllText(moduleSourcePath!);
+
+ // Extract the AgentObservationAdded handler body. The
+ // method ends at the matching close-brace of the
+ // `try { ... } finally { ... }` pair, which is the last
+ // brace at column 8 before the next `private` member.
+ var startIndex = source.IndexOf(
+ "private async void AgentObservationAdded",
+ StringComparison.Ordinal);
+ Assert.That(startIndex, Is.GreaterThanOrEqualTo(0),
+ "AgentObservationAdded handler not found in Module.cs.");
+
+ // Find the start of the next private member after the
+ // handler so we scope the scan to AgentObservationAdded's
+ // body and don't reach into AgentAssetAdded.
+ var nextMemberIndex = source.IndexOf(
+ "private async void AgentAssetAdded",
+ startIndex, StringComparison.Ordinal);
+ Assert.That(nextMemberIndex, Is.GreaterThan(startIndex),
+ "Next handler AgentAssetAdded not found after AgentObservationAdded; " +
+ "Module.cs structure has changed.");
+
+ var handlerBody = source.Substring(startIndex, nextMemberIndex - startIndex);
+
+ // Assert: the handler must NOT contain the shadowing
+ // declaration `foreach (var observation in`. The renamed
+ // form uses a different identifier such as
+ // `condObservation`.
+ var shadowingPatterns = new[]
+ {
+ "foreach (var observation in",
+ "foreach(var observation in",
+ };
+ foreach (var pattern in shadowingPatterns)
+ {
+ Assert.That(
+ handlerBody.Contains(pattern, StringComparison.Ordinal),
+ Is.False,
+ $"AgentObservationAdded contains `{pattern}` which shadows " +
+ "the outer `observation` parameter and fails CS0136 under net4x. " +
+ "Rename the inner loop variable.");
+ }
+ }
+
+ private static string FindModuleSourcePath()
+ {
+ // The test assembly's location lives under
+ // tests/MTConnect.NET-AgentModule-MqttRelay-Tests/bin/...
+ // walk up to find the repo root marker, then descend.
+ var dir = new DirectoryInfo(AppContext.BaseDirectory);
+ while (dir != null)
+ {
+ var candidate = Path.Combine(
+ dir.FullName,
+ "agent", "Modules", "MTConnect.NET-AgentModule-MqttRelay", "Module.cs");
+ if (File.Exists(candidate)) return candidate;
+ dir = dir.Parent;
+ }
+ return null;
+ }
+ }
+}
diff --git a/tests/MTConnect.NET-Common-Tests/MTConnect.NET-Common-Tests.csproj b/tests/MTConnect.NET-Common-Tests/MTConnect.NET-Common-Tests.csproj
index e06ed7bd0..b49ea509f 100644
--- a/tests/MTConnect.NET-Common-Tests/MTConnect.NET-Common-Tests.csproj
+++ b/tests/MTConnect.NET-Common-Tests/MTConnect.NET-Common-Tests.csproj
@@ -17,6 +17,20 @@
+
+
+
+
+
diff --git a/tests/MTConnect.NET-Common-Tests/Platform/SupportedOSPlatformAttributePresenceTests.cs b/tests/MTConnect.NET-Common-Tests/Platform/SupportedOSPlatformAttributePresenceTests.cs
new file mode 100644
index 000000000..0c08593fe
--- /dev/null
+++ b/tests/MTConnect.NET-Common-Tests/Platform/SupportedOSPlatformAttributePresenceTests.cs
@@ -0,0 +1,156 @@
+// Copyright (c) 2026 TrakHound Inc., All Rights Reserved.
+// TrakHound Inc. licenses this file to you under the MIT license.
+
+using System;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Versioning;
+using NUnit.Framework;
+
+namespace MTConnect.NET_Common_Tests.Platform
+{
+ // Pins the [SupportedOSPlatform("windows")] decoration on every type or
+ // method that was annotated by commit dd2eb424 (2026-05-22) to silence
+ // the CA1416 platform-compatibility analyzer on .NET 8. The attribute
+ // type ships in System.Runtime on .NET 5.0+ but is absent from net4x
+ // and netstandard2.0; PR #194 wraps each declaration plus its
+ // using-directive in `#if NET5_0_OR_GREATER ... #endif` so the
+ // Release pack survives the full TFM matrix.
+ //
+ // This fixture only exercises the net8.0 build path (the only TFM
+ // every test project targets), and so cannot directly fail under the
+ // pre-fix code (net8.0 keeps the attribute regardless of the wrap).
+ // Its value is REGRESSION-PREVENTIVE: a future contributor who
+ // removes the attribute outright — or who narrows the wrap to a
+ // condition that excludes net8.0 — fails this test, and the
+ // protection the original commit added stays in place.
+ /// Pins SupportedOSPlatform("windows") on every site PR #194 wraps.
+ [TestFixture]
+ [Category("MultiTfmCompat")]
+ public class SupportedOSPlatformAttributePresenceTests
+ {
+ private static void AssertWindowsPlatform(MemberInfo member, string description)
+ {
+ var attributes = member
+ .GetCustomAttributes(typeof(SupportedOSPlatformAttribute), inherit: false)
+ .Cast()
+ .ToArray();
+
+ Assert.That(attributes, Is.Not.Empty,
+ $"{description}: expected [SupportedOSPlatform] attribute.");
+ Assert.That(
+ attributes.Any(a => string.Equals(a.PlatformName, "windows", StringComparison.Ordinal)),
+ Is.True,
+ $"{description}: expected PlatformName == \"windows\" but got " +
+ $"[{string.Join(", ", attributes.Select(a => a.PlatformName))}].");
+ }
+
+ /// MTConnect.Services.WindowsService carries the Windows-only attribute.
+ [Test]
+ public void WindowsService_carries_supported_os_platform_windows()
+ {
+ // WindowsService is internal — reach it via Assembly.GetType
+ // rather than typeof(...).
+ var servicesAssembly = typeof(MTConnect.Services.MTConnectAgentService).Assembly;
+ var windowsServiceType = servicesAssembly.GetType(
+ "MTConnect.Services.WindowsService", throwOnError: true);
+ AssertWindowsPlatform(windowsServiceType!,
+ "MTConnect.Services.WindowsService");
+ }
+
+ /// MTConnect.Services.MTConnectAgentService carries the Windows-only attribute.
+ [Test]
+ public void MTConnectAgentService_carries_supported_os_platform_windows()
+ {
+ AssertWindowsPlatform(typeof(MTConnect.Services.MTConnectAgentService),
+ "MTConnect.Services.MTConnectAgentService");
+ }
+
+ /// MTConnect.Services.MTConnectAdapterService carries the Windows-only attribute.
+ [Test]
+ public void MTConnectAdapterService_carries_supported_os_platform_windows()
+ {
+ AssertWindowsPlatform(typeof(MTConnect.Services.MTConnectAdapterService),
+ "MTConnect.Services.MTConnectAdapterService");
+ }
+
+ /// The agent-application Service class carries the Windows-only attribute.
+ [Test]
+ public void AgentApplications_Service_carries_supported_os_platform_windows()
+ {
+ // Both agent-application and adapter-application Service
+ // types live under the same MTConnect.Applications
+ // namespace; distinguish by assembly.
+ var agentServiceType = typeof(MTConnect.Applications.IMTConnectAgentApplication).Assembly
+ .GetType("MTConnect.Applications.Service", throwOnError: true);
+ AssertWindowsPlatform(agentServiceType!,
+ "MTConnect.Applications.Service (agent application)");
+ }
+
+ /// The adapter-application Service class carries the Windows-only attribute.
+ [Test]
+ public void AdapterApplications_Service_carries_supported_os_platform_windows()
+ {
+ var adapterServiceType = typeof(MTConnect.Applications.IMTConnectAdapterApplication).Assembly
+ .GetType("MTConnect.Applications.Service", throwOnError: true);
+ AssertWindowsPlatform(adapterServiceType!,
+ "MTConnect.Applications.Service (adapter application)");
+ }
+
+ /// The Ceen HTTP-server socket-handle sites carry the Windows-only attribute.
+ [Test]
+ public void CeenHttpServer_socket_handle_sites_carry_supported_os_platform_windows()
+ {
+ // Both annotated members are internal to MTConnect.NET-HTTP:
+ // * Ceen.Httpd.HttpServer.InterProcessBridge.HandleRequest
+ // * Ceen.Httpd.HttpServer.RunClient (private static)
+ // Reach them via Assembly.GetType + reflection.
+ var httpAssembly = typeof(MTConnect.Servers.Http.MTConnectHttpRequests).Assembly;
+ var httpServerType = httpAssembly.GetType(
+ "Ceen.Httpd.HttpServer", throwOnError: true)!;
+ var socketInformationType = typeof(System.Net.Sockets.SocketInformation);
+
+ // The [SupportedOSPlatform("windows")] attribute lives on
+ // Ceen.Httpd.HttpServer.AppDomainBridge.HandleRequest(
+ // SocketInformation, EndPoint, string) — AppDomainBridge,
+ // not InterProcessBridge, is the AppDomain-marshallable
+ // sibling that wraps the duplicated socket handle. The
+ // RunClient(SocketInformation,...) private static method on
+ // HttpServer itself is the second site.
+ var bridgeType = httpServerType.GetNestedType(
+ "AppDomainBridge", BindingFlags.Public | BindingFlags.NonPublic);
+ Assert.That(bridgeType, Is.Not.Null,
+ "Ceen.Httpd.HttpServer.AppDomainBridge nested type not found.");
+
+ const BindingFlags allInstance = BindingFlags.Public | BindingFlags.NonPublic
+ | BindingFlags.Instance;
+ // HandleRequest has two overloads; the SocketInformation-typed
+ // one is the Windows-only path the attribute decorates. The
+ // Socket-typed overload is cross-platform.
+ var handleRequestCandidates = bridgeType!.GetMethods(allInstance)
+ .Where(m => m.Name == "HandleRequest")
+ .ToArray();
+ var handleRequest = handleRequestCandidates
+ .FirstOrDefault(m => m.GetParameters().Length > 0
+ && m.GetParameters()[0].ParameterType == socketInformationType);
+ Assert.That(handleRequest, Is.Not.Null,
+ "Ceen.Httpd.HttpServer.AppDomainBridge.HandleRequest(SocketInformation,...) overload not found among: " +
+ string.Join("; ",
+ handleRequestCandidates.Select(m => $"{m.Name}({string.Join(",", m.GetParameters().Select(p => p.ParameterType.FullName))})")));
+
+ const BindingFlags allStatic = BindingFlags.Public | BindingFlags.NonPublic
+ | BindingFlags.Static;
+ var runClient = httpServerType.GetMethods(allStatic)
+ .FirstOrDefault(m => m.Name == "RunClient"
+ && m.GetParameters().Length > 0
+ && m.GetParameters()[0].ParameterType == socketInformationType);
+ Assert.That(runClient, Is.Not.Null,
+ "Ceen.Httpd.HttpServer.RunClient(SocketInformation,...) overload not found.");
+
+ AssertWindowsPlatform(handleRequest!,
+ "Ceen.Httpd.HttpServer.AppDomainBridge.HandleRequest");
+ AssertWindowsPlatform(runClient!,
+ "Ceen.Httpd.HttpServer.RunClient(SocketInformation,...)");
+ }
+ }
+}
diff --git a/tests/MTConnect.NET-XML-Tests/Xml/UsingDeclarationsTests.cs b/tests/MTConnect.NET-XML-Tests/Xml/UsingDeclarationsTests.cs
new file mode 100644
index 000000000..c028cfa08
--- /dev/null
+++ b/tests/MTConnect.NET-XML-Tests/Xml/UsingDeclarationsTests.cs
@@ -0,0 +1,82 @@
+// Copyright (c) 2026 TrakHound Inc., All Rights Reserved.
+// TrakHound Inc. licenses this file to you under the MIT license.
+
+using NUnit.Framework;
+
+namespace MTConnect.Tests.XML.Xml
+{
+ // Pins the C# 8.0 `using` declaration code path in
+ // MTConnect.NET-XML. The production site lives in
+ // XsdPreprocessor.StripXsd11Constructs:
+ //
+ // using var reader = new StringReader(xsdSourceXml);
+ //
+ // C# 8.0 added the using-declaration form; on netstandard2.0 the
+ // compiler's default LangVersion is 7.3, which rejects that syntax
+ // with CS8370. PR #194 pins the project's LangVersion to 8.0 so the
+ // Release pack survives the full TFM matrix; this fixture exercises
+ // the path so a regression that breaks the preprocessor's load step
+ // surfaces as a test failure rather than only as a build break.
+ //
+ // The fixture compiles and runs under net8.0 — the only TFM every
+ // test project targets — so the test passes regardless of
+ // LangVersion. Its value is to ensure the production code path
+ // stays exercised, matching the brief's TDD shape for paths whose
+ // pre-fix surface is already correct on the test TFM.
+ /// Pins the C# 8.0 using-declaration path in XsdPreprocessor.
+ [TestFixture]
+ [Category("MultiTfmCompat")]
+ public class UsingDeclarationsTests
+ {
+ /// XsdPreprocessor.StripXsd11Constructs accepts a minimal well-formed XSD.
+ [Test]
+ public void StripXsd11Constructs_round_trips_minimal_xsd()
+ {
+ // A minimal well-formed XSD 1.0 schema with no 1.1-only
+ // constructs round-trips through StripXsd11Constructs
+ // unchanged structurally. The path exercised here is the
+ // using-declaration body that disposes the StringReader.
+ const string minimalXsd =
+ "\n" +
+ "\n" +
+ " \n" +
+ "";
+
+ var result = XsdPreprocessor.StripXsd11Constructs(minimalXsd);
+
+ Assert.That(result, Is.Not.Null,
+ "StripXsd11Constructs must return a non-null result for valid input.");
+ Assert.That(result, Does.Contain("Root"),
+ "The minimal schema's element name must round-trip through the preprocessor.");
+ }
+
+ /// XsdPreprocessor.StripXsd11Constructs strips the 1.1-only xs:assert element.
+ [Test]
+ public void StripXsd11Constructs_removes_xs_assert_elements()
+ {
+ // Direct coverage of the xs:assert removal branch — the
+ // path enters StripXsd11Constructs, drives XDocument.Load
+ // through the using-declared StringReader, and exits with
+ // the xs:assert element removed.
+ const string xsdWithAssert =
+ "\n" +
+ "\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ "";
+
+ var result = XsdPreprocessor.StripXsd11Constructs(xsdWithAssert);
+
+ Assert.That(result, Does.Not.Contain("xs:assert"),
+ "xs:assert must be stripped by the preprocessor.");
+ Assert.That(result, Does.Contain("WithAssert"),
+ "The enclosing complexType must survive the assertion stripping.");
+ }
+ }
+}