From 4b36b357eaa21d0c1bd0a4abb9484b17c27277ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 08:00:58 +0200 Subject: [PATCH 01/29] feat(docs): expand docfx coverage to every committed project Grow the API reference from the 13 shipped libraries to every committed .csproj in the repo: agent and adapter applications and modules, in-tree generator and builder tools, the four standalone examples, the embedded-agent template content project, and the ten test suites. The audience comment on generate-api-ref.sh is broadened from 'libraries' to 'every committed project'. The script's project list now uses path-prefixed entries with an optional ':csproj' suffix for the project whose csproj filename diverges from the directory name (the embedded-agent template content). Reference output grows from ~1881 pages on the 13-library subset to the full repo surface. --- docs/.docfx/docfx.json | 22 ++++++++++++- docs/scripts/generate-api-ref.sh | 55 +++++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/docs/.docfx/docfx.json b/docs/.docfx/docfx.json index f1f8187ed..230da036d 100644 --- a/docs/.docfx/docfx.json +++ b/docs/.docfx/docfx.json @@ -25,10 +25,30 @@ "agent/Modules/MTConnect.NET-AgentModule-MqttBroker/bin/Debug/net8.0/MTConnect.NET-AgentModule-MqttBroker.dll", "agent/Modules/MTConnect.NET-AgentModule-MqttRelay/bin/Debug/net8.0/MTConnect.NET-AgentModule-MqttRelay.dll", "agent/Modules/MTConnect.NET-AgentModule-ShdrAdapter/bin/Debug/net8.0/MTConnect.NET-AgentModule-ShdrAdapter.dll", + "agent/Processors/MTConnect.NET-AgentProcessor-Python/bin/Debug/net8.0/MTConnect.NET-AgentProcessor-Python.dll", "adapter/MTConnect.NET-Adapter/bin/Debug/net8.0/MTConnect.NET-Adapter.dll", "adapter/MTConnect.NET-Applications-Adapter/bin/Debug/net8.0/MTConnect.NET-Applications-Adapter.dll", "adapter/Modules/MTConnect.NET-AdapterModule-MQTT/bin/Debug/net8.0/MTConnect.NET-AdapterModule-MQTT.dll", - "adapter/Modules/MTConnect.NET-AdapterModule-SHDR/bin/Debug/net8.0/MTConnect.NET-AdapterModule-SHDR.dll" + "adapter/Modules/MTConnect.NET-AdapterModule-SHDR/bin/Debug/net8.0/MTConnect.NET-AdapterModule-SHDR.dll", + "build/MTConnect.NET-SysML-Import/bin/Debug/net8.0/MTConnect.NET-SysML-Import.dll", + "build/MTConnect.NET-DocsGen/bin/Debug/net8.0/MTConnect.NET-DocsGen.dll", + "build/MTConnect.NET.Builder/bin/Debug/net8.0/MTConnect.NET.Builder.dll", + "examples/MTConnect.NET-Agent-Embedded/bin/Debug/net8.0/MTConnect.NET-Agent-Embedded.dll", + "examples/MTConnect.NET-Client-HTTP/bin/Debug/net8.0/MTConnect.NET-Client-HTTP.dll", + "examples/MTConnect.NET-Client-MQTT/bin/Debug/net8.0/MTConnect.NET-Client-MQTT.dll", + "examples/MTConnect.NET-Client-SHDR/bin/Debug/net8.0/MTConnect.NET-Client-SHDR.dll", + "templates/mtconnect.net-agent/content/MTConnect.NET-Embedded-Agent/bin/Debug/net8.0/agent.dll", + "tests/Compliance/MTConnect-Compliance-Tests/bin/Debug/net8.0/MTConnect-Compliance-Tests.dll", + "tests/MTConnect.NET-AgentModule-MqttRelay-Tests/bin/Debug/net8.0/MTConnect.NET-AgentModule-MqttRelay-Tests.dll", + "tests/MTConnect.NET-Common-Tests/bin/Debug/net8.0/MTConnect.NET-Common-Tests.dll", + "tests/MTConnect.NET-Docs-Tests/bin/Debug/net8.0/MTConnect.NET-Docs-Tests.dll", + "tests/MTConnect.NET-HTTP-Tests/bin/Debug/net8.0/MTConnect.NET-HTTP-Tests.dll", + "tests/MTConnect.NET-Integration-Tests/bin/Debug/net8.0/MTConnect.NET-Integration-Tests.dll", + "tests/MTConnect.NET-JSON-cppagent-Tests/bin/Debug/net8.0/MTConnect.NET-JSON-cppagent-Tests.dll", + "tests/MTConnect.NET-JSON-Tests/bin/Debug/net8.0/MTConnect.NET-JSON-Tests.dll", + "tests/MTConnect.NET-SHDR-Tests/bin/Debug/net8.0/MTConnect.NET-SHDR-Tests.dll", + "tests/MTConnect.NET-Tests-Agents/bin/Debug/net8.0/MTConnect.NET-Tests-Agents.dll", + "tests/MTConnect.NET-XML-Tests/bin/Debug/net8.0/MTConnect.NET-XML-Tests.dll" ], "src": "../.." } diff --git a/docs/scripts/generate-api-ref.sh b/docs/scripts/generate-api-ref.sh index a13cb574c..dc3187e2a 100755 --- a/docs/scripts/generate-api-ref.sh +++ b/docs/scripts/generate-api-ref.sh @@ -1,9 +1,11 @@ #!/usr/bin/env bash # Generate the API reference Markdown under docs/api/. # -# Compiles every shipped MTConnect.NET library in Release / net8.0, -# then runs `docfx metadata` against the produced DLLs and XML doc -# files. The output is a flat tree of `Namespace.Type.md` pages +# Compiles every committed MTConnect.NET project (libraries, agent and +# adapter applications and modules, in-tree build / generator tools, +# examples, the embedded-agent template, and the test suites) in +# Debug, then runs `docfx metadata` against the produced DLLs and XML +# doc files. The output is a flat tree of `Namespace.Type.md` pages # alongside per-namespace landing pages. # # Usage: @@ -24,7 +26,7 @@ for arg in "$@"; do case "${arg}" in --fast) skip_build=true ;; -h|--help) - sed -n '2,15p' "${BASH_SOURCE[0]}" + sed -n '2,17p' "${BASH_SOURCE[0]}" exit 0 ;; *) @@ -34,6 +36,9 @@ for arg in "$@"; do esac done +# Path to the project directory. The csproj filename is inferred as +# ".csproj" except where overridden in the matching entries +# of csproj_overrides below. projects=( "libraries/MTConnect.NET-Common" "libraries/MTConnect.NET-DeviceFinder" @@ -56,21 +61,47 @@ projects=( "agent/Modules/MTConnect.NET-AgentModule-MqttBroker" "agent/Modules/MTConnect.NET-AgentModule-MqttRelay" "agent/Modules/MTConnect.NET-AgentModule-ShdrAdapter" + "agent/Processors/MTConnect.NET-AgentProcessor-Python" "adapter/MTConnect.NET-Adapter" "adapter/MTConnect.NET-Applications-Adapter" "adapter/Modules/MTConnect.NET-AdapterModule-MQTT" "adapter/Modules/MTConnect.NET-AdapterModule-SHDR" + "build/MTConnect.NET-SysML-Import" + "build/MTConnect.NET-DocsGen" + "build/MTConnect.NET.Builder" + "examples/MTConnect.NET-Agent-Embedded" + "examples/MTConnect.NET-Client-HTTP" + "examples/MTConnect.NET-Client-MQTT" + "examples/MTConnect.NET-Client-SHDR" + "templates/mtconnect.net-agent/content/MTConnect.NET-Embedded-Agent:Agent.csproj" + "tests/Compliance/MTConnect-Compliance-Tests" + "tests/MTConnect.NET-AgentModule-MqttRelay-Tests" + "tests/MTConnect.NET-Common-Tests" + "tests/MTConnect.NET-Docs-Tests" + "tests/MTConnect.NET-HTTP-Tests" + "tests/MTConnect.NET-Integration-Tests" + "tests/MTConnect.NET-JSON-cppagent-Tests" + "tests/MTConnect.NET-JSON-Tests" + "tests/MTConnect.NET-SHDR-Tests" + "tests/MTConnect.NET-Tests-Agents" + "tests/MTConnect.NET-XML-Tests" ) if ! "${skip_build}"; then - echo "==> building projects in Debug for net8.0" - # Debug is the multi-target config that compiles ONLY net8.0 on every - # project — Release multi-targets net4.6.1..net9.0 and fails on SDKs - # that lack the legacy reference assemblies. The reference is content, - # not packaged output, so a Debug build is fine. - for proj in "${projects[@]}"; do - name="$(basename "${proj}")" - dotnet build "${proj}/${name}.csproj" \ + echo "==> building projects in Debug" + # Debug is the multi-target config that compiles ONLY net8.0 on + # every shipped project — Release multi-targets net4.6.1..net9.0 and + # fails on SDKs that lack the legacy reference assemblies. The + # reference is content, not packaged output, so a Debug build is + # fine. + for entry in "${projects[@]}"; do + proj_dir="${entry%%:*}" + if [[ "${entry}" == *:* ]]; then + csproj_name="${entry##*:}" + else + csproj_name="$(basename "${proj_dir}").csproj" + fi + dotnet build "${proj_dir}/${csproj_name}" \ -c Debug \ -p:GenerateDocumentationFile=true \ -p:AdditionalNoWarn=CS1591 \ From f9a52ee2fdb2fe5afd96bff76854c49758d4cc06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 10:45:24 +0200 Subject: [PATCH 02/29] chore(tools): narrow NoWarn to CS1591 only in api-ref regen --- docs/scripts/generate-api-ref.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/scripts/generate-api-ref.sh b/docs/scripts/generate-api-ref.sh index dc3187e2a..65190cc04 100755 --- a/docs/scripts/generate-api-ref.sh +++ b/docs/scripts/generate-api-ref.sh @@ -101,9 +101,16 @@ if ! "${skip_build}"; then else csproj_name="$(basename "${proj_dir}").csproj" fi + # Suppress only CS1591 (missing XML doc on public surface). Every + # other XML-doc warning family is treated as a hard error so the + # regen surfaces broken comments rather than silently masking them. + # AdditionalNoWarn is honoured by libraries/Directory.Build.props but + # not by test/agent/adapter projects, so feed CS1591 to NoWarn + # directly to cover the whole tree. dotnet build "${proj_dir}/${csproj_name}" \ -c Debug \ -p:GenerateDocumentationFile=true \ + -p:NoWarn=CS1591 \ -p:AdditionalNoWarn=CS1591 \ --nologo \ -v:quiet From e39fae262ada64caaf17f3b59c88143e1e927216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 10:45:25 +0200 Subject: [PATCH 03/29] docs(api): align XML doc cref and paramref with current signatures --- .../MTConnect.NET-DeviceFinder/MTConnectDeviceFinder.cs | 2 +- .../Clients/MTConnectHttpCurrentClient.cs | 2 +- .../MTConnect.NET-HTTP/Clients/MTConnectHttpProbeClient.cs | 2 +- .../MTConnect.NET-HTTP/Clients/MTConnectHttpSampleClient.cs | 2 +- libraries/MTConnect.NET-JSON-cppagent/Streams/JsonCell.cs | 2 +- .../IMTConnectMqttDocumentServerConfiguration.cs | 2 +- .../IMTConnectMqttEntityServerConfiguration.cs | 2 +- libraries/MTConnect.NET-SHDR/Shdr/ShdrDevice.cs | 2 +- .../Agents/AgentUuidDeterministicDefaultTests.cs | 6 +++--- .../Assets/Pallet/PalletMeasurementContractTests.cs | 2 +- .../Devices/DeviceCtorStartupValidationTests.cs | 2 +- .../TestHelpers/ComponentDepthFinder.cs | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libraries/MTConnect.NET-DeviceFinder/MTConnectDeviceFinder.cs b/libraries/MTConnect.NET-DeviceFinder/MTConnectDeviceFinder.cs index ea9ec7b7a..71e77c25f 100644 --- a/libraries/MTConnect.NET-DeviceFinder/MTConnectDeviceFinder.cs +++ b/libraries/MTConnect.NET-DeviceFinder/MTConnectDeviceFinder.cs @@ -125,7 +125,7 @@ public class MTConnectDeviceFinder public event RequestStatusHandler SearchCompleted; - /// Constructs the finder bound to the first reachable network interface; call after configuring and . + /// Constructs the finder bound to the first reachable network interface; call after configuring and . public MTConnectDeviceFinder() { Init(); diff --git a/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpCurrentClient.cs b/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpCurrentClient.cs index f77cd5cd7..5d681081c 100644 --- a/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpCurrentClient.cs +++ b/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpCurrentClient.cs @@ -266,7 +266,7 @@ public async Task GetAsync(CancellationToken cancellat } - /// Builds the current request URI from the client's own , , , , and . + /// Builds the current request URI from the client's own , , , , and . public Uri CreateUri() => CreateUri(Authority, Device, Path, At, DocumentFormat); /// Convenience overload that passes 0 for , taking the port from if present. diff --git a/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpProbeClient.cs b/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpProbeClient.cs index 0f86e80fa..e34729c91 100644 --- a/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpProbeClient.cs +++ b/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpProbeClient.cs @@ -313,7 +313,7 @@ public async Task GetAsync(CancellationToken cancellat } - /// Builds the probe request URI from the client's own , , and . + /// Builds the probe request URI from the client's own , , and . public Uri CreateUri() => CreateUri(Authority, Device, DocumentFormat); /// Convenience overload that passes 0 for , taking the port from if present. diff --git a/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpSampleClient.cs b/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpSampleClient.cs index a0da5520f..7a0535003 100644 --- a/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpSampleClient.cs +++ b/libraries/MTConnect.NET-HTTP/Clients/MTConnectHttpSampleClient.cs @@ -283,7 +283,7 @@ public async Task GetAsync(CancellationToken cancel) } - /// Builds the sample request URI from the client's own , , , , , , and . + /// Builds the sample request URI from the client's own , , , , , , and . public Uri CreateUri() => CreateUri(Authority, Device, Path, From, To, Count, DocumentFormat); /// Convenience overload that passes 0 for , so the port is taken from if it carries one. diff --git a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonCell.cs b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonCell.cs index fc77f137e..6317e67df 100644 --- a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonCell.cs +++ b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonCell.cs @@ -10,7 +10,7 @@ namespace MTConnect.Streams.Json /// JSON serialization surrogate for a single cell of a table-entry /// observation. Carried inside a 's cell /// list when expressed as discrete cell objects, before the parent - /// converter collapses cells into + /// converter collapses cells into /// the row dictionary on emission. /// public class JsonCell diff --git a/libraries/MTConnect.NET-MQTT/Configurations/IMTConnectMqttDocumentServerConfiguration.cs b/libraries/MTConnect.NET-MQTT/Configurations/IMTConnectMqttDocumentServerConfiguration.cs index 291b40bc7..3eb17df00 100644 --- a/libraries/MTConnect.NET-MQTT/Configurations/IMTConnectMqttDocumentServerConfiguration.cs +++ b/libraries/MTConnect.NET-MQTT/Configurations/IMTConnectMqttDocumentServerConfiguration.cs @@ -4,7 +4,7 @@ namespace MTConnect.Configurations { /// - /// Settings consumed by that publish + /// Settings consumed by MTConnect.Mqtt.MTConnectMqttDocumentServer (defined in the agent MQTT modules) that publish /// the full MTConnect response documents (Probe, Current, Sample, Asset) over MQTT rather /// than individual observation topics. Configures only the publish cadence; the topic layout /// is defined by the concrete configuration class. diff --git a/libraries/MTConnect.NET-MQTT/Configurations/IMTConnectMqttEntityServerConfiguration.cs b/libraries/MTConnect.NET-MQTT/Configurations/IMTConnectMqttEntityServerConfiguration.cs index 5f93c7335..ded34cad2 100644 --- a/libraries/MTConnect.NET-MQTT/Configurations/IMTConnectMqttEntityServerConfiguration.cs +++ b/libraries/MTConnect.NET-MQTT/Configurations/IMTConnectMqttEntityServerConfiguration.cs @@ -4,7 +4,7 @@ namespace MTConnect.Configurations { /// - /// Settings consumed by that publish + /// Settings consumed by MTConnect.Mqtt.MTConnectMqttEntityServer (defined in the agent MQTT modules) that publish /// individual MTConnect entities (devices, observations, assets) under per-entity topics /// rather than as packaged response documents. Configures the topic prefix, the serialisation /// format, and the MQTT QoS for all entity publishes. diff --git a/libraries/MTConnect.NET-SHDR/Shdr/ShdrDevice.cs b/libraries/MTConnect.NET-SHDR/Shdr/ShdrDevice.cs index 9a73d25a2..93a0450da 100644 --- a/libraries/MTConnect.NET-SHDR/Shdr/ShdrDevice.cs +++ b/libraries/MTConnect.NET-SHDR/Shdr/ShdrDevice.cs @@ -83,7 +83,7 @@ public ShdrDevice(string deviceUuid, string xml) Xml = xml; } - /// Creates an SHDR device wrapping the supplied ; if its is empty a fresh GUID is assigned. + /// Creates an SHDR device wrapping the supplied ; if its is empty a fresh GUID is assigned. public ShdrDevice(IDevice device) { if (device != null) diff --git a/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidDeterministicDefaultTests.cs b/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidDeterministicDefaultTests.cs index 9f9e6a95d..44da25058 100644 --- a/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidDeterministicDefaultTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidDeterministicDefaultTests.cs @@ -23,7 +23,7 @@ namespace MTConnect.Tests.Common.Agents /// name_generator prior art. /// /// These tests do not drive MTConnectAgentApplication.StartAgent - /// end-to-end. Instead, replays the fresh-construction + /// end-to-end. Instead, a SimulateBoot helper replays the fresh-construction /// path deterministically so the invariants are pinned at the unit level. /// [TestFixture] @@ -130,7 +130,7 @@ public void DeriveFromSeed_matches_python_uuid_v5_NAMESPACE_DNS_example_com_vect /// /// Two consecutive fresh boots (no state file, no config override) - /// with the same must produce identical + /// with the same agentName must produce identical /// UUIDs — satisfying UuidType's "for it's entire life" annotation /// across ephemeral-container restarts. /// @@ -177,7 +177,7 @@ public void Default_agent_uuid_is_valid_uuid_v5_format() } /// - /// Two fresh boots with distinct values must + /// Two fresh boots with distinct agentName values must /// produce distinct UUIDs, confirming that the seed differentiates agents. /// [Test] diff --git a/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs b/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs index 8d87303e8..47d6d107b 100644 --- a/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs @@ -31,7 +31,7 @@ namespace MTConnect.Tests.Common.Assets.Pallet /// /// /// Sources: - /// - SysML XMI: + /// - SysML XMI: https://github.com/mtconnect/mtconnect_sysml_model /// v2.7. The Pallet measurement subclasses sit under UML package /// "Asset Information Model > Pallet > Measurements" with the /// abstract base UML ID diff --git a/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorStartupValidationTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorStartupValidationTests.cs index 80c93cf6b..397264c57 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorStartupValidationTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorStartupValidationTests.cs @@ -9,7 +9,7 @@ namespace MTConnect.Tests.Common.DeviceCtorDefaults { /// /// Pins the startup-time invariant that - /// rejects any Device whose is null or empty. + /// rejects any Device whose is null or empty. /// /// Background: the parameterless ctor leaves /// Id, Name, and Uuid all null so the ctor does diff --git a/tests/MTConnect.NET-Common-Tests/TestHelpers/ComponentDepthFinder.cs b/tests/MTConnect.NET-Common-Tests/TestHelpers/ComponentDepthFinder.cs index b8eebcbb4..b85a2e159 100644 --- a/tests/MTConnect.NET-Common-Tests/TestHelpers/ComponentDepthFinder.cs +++ b/tests/MTConnect.NET-Common-Tests/TestHelpers/ComponentDepthFinder.cs @@ -10,7 +10,7 @@ namespace MTConnect.Tests.Common.TestHelpers /// /// Walks a Device component tree depth-first and returns the depth /// (1-based) of the first whose - /// Type equals . Returns + /// Type equals the supplied targetTypeId. Returns /// -1 when the target is not present in the subtree. /// /// Tests that need to assert tree-depth invariants for the auto-wrap From 4e8848c54d329e36f1d7962a5bc69df9da45e98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 11:56:23 +0200 Subject: [PATCH 04/29] revert(tools): remove CS1591 suppression in api-ref regen --- docs/scripts/generate-api-ref.sh | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/scripts/generate-api-ref.sh b/docs/scripts/generate-api-ref.sh index 65190cc04..b97385ae8 100755 --- a/docs/scripts/generate-api-ref.sh +++ b/docs/scripts/generate-api-ref.sh @@ -101,17 +101,13 @@ if ! "${skip_build}"; then else csproj_name="$(basename "${proj_dir}").csproj" fi - # Suppress only CS1591 (missing XML doc on public surface). Every - # other XML-doc warning family is treated as a hard error so the - # regen surfaces broken comments rather than silently masking them. - # AdditionalNoWarn is honoured by libraries/Directory.Build.props but - # not by test/agent/adapter projects, so feed CS1591 to NoWarn - # directly to cover the whole tree. + # Pass no NoWarn overrides. TreatWarningsAsErrors=true in + # Directory.Build.props turns every XML-doc warning — including + # CS1591 (missing XML doc on a public surface) — into a build + # failure, which is the campaign's 100 % XML-doc-coverage gate. dotnet build "${proj_dir}/${csproj_name}" \ -c Debug \ -p:GenerateDocumentationFile=true \ - -p:NoWarn=CS1591 \ - -p:AdditionalNoWarn=CS1591 \ --nologo \ -v:quiet done From 46b006d237e3bdf280fb573bfff31220fdd5ca16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:12:51 +0200 Subject: [PATCH 05/29] fix(tools): force --no-incremental to surface CS1591 reliably --- docs/scripts/generate-api-ref.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/scripts/generate-api-ref.sh b/docs/scripts/generate-api-ref.sh index b97385ae8..7567af503 100755 --- a/docs/scripts/generate-api-ref.sh +++ b/docs/scripts/generate-api-ref.sh @@ -105,9 +105,17 @@ if ! "${skip_build}"; then # Directory.Build.props turns every XML-doc warning — including # CS1591 (missing XML doc on a public surface) — into a build # failure, which is the campaign's 100 % XML-doc-coverage gate. + # + # --no-incremental forces a from-source recompile. Without it, + # an obj/ tree that was last produced under a CS1591-suppressed + # build remains current and silently masks missing-doc errors: + # MSBuild's up-to-date check looks at file timestamps and skips + # csc altogether, so neither the new compiler flags nor the + # diagnostic list takes effect. dotnet build "${proj_dir}/${csproj_name}" \ -c Debug \ -p:GenerateDocumentationFile=true \ + --no-incremental \ --nologo \ -v:quiet done From c9374966c7f07ca133f6fc78711425512ef34a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:16:39 +0200 Subject: [PATCH 06/29] docs(examples): author XML doc comments on Agent-Embedded surface --- examples/MTConnect.NET-Agent-Embedded/Program.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/MTConnect.NET-Agent-Embedded/Program.cs b/examples/MTConnect.NET-Agent-Embedded/Program.cs index fcc30c323..c5bbafbc2 100644 --- a/examples/MTConnect.NET-Agent-Embedded/Program.cs +++ b/examples/MTConnect.NET-Agent-Embedded/Program.cs @@ -14,10 +14,14 @@ // [ Module Configuration ] // This is where you can create a custom configuration section +/// Represents the module configuration. public class ModuleConfiguration { + /// Gets or sets the device uuid. public string DeviceUuid { get; set; } + /// Gets or sets the device name. public string DeviceName { get; set; } + /// Gets or sets the serial number. public string SerialNumber { get; set; } } @@ -25,13 +29,19 @@ public class ModuleConfiguration // [ Agent Module ] // This is the module that runs your code +/// Represents the module. public class Module : MTConnectInputAgentModule { + /// The configuration type id. public const string ConfigurationTypeId = "datasource"; // This must match the module section in the 'agent.config.yaml' file + /// The default id. public const string DefaultId = "DataSource Module"; // The ID is mainly just used for logging. private readonly ModuleConfiguration _configuration; + /// Initialises a new instance of the module type. + /// The agent. + /// The configuration. public Module(IMTConnectAgentBroker agent, object configuration) : base(agent) { Id = DefaultId; From e6217392d8e26d1f91521890b440e5d370b5b979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:17:16 +0200 Subject: [PATCH 07/29] docs(templates): author XML doc comments on embedded-agent template --- .../content/MTConnect.NET-Embedded-Agent/Program.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/templates/mtconnect.net-agent/content/MTConnect.NET-Embedded-Agent/Program.cs b/templates/mtconnect.net-agent/content/MTConnect.NET-Embedded-Agent/Program.cs index d01f46e3e..5d0658c87 100644 --- a/templates/mtconnect.net-agent/content/MTConnect.NET-Embedded-Agent/Program.cs +++ b/templates/mtconnect.net-agent/content/MTConnect.NET-Embedded-Agent/Program.cs @@ -7,6 +7,7 @@ namespace MTConnectAgent { + /// Represents the program. public class Program { static void Main(string[] args) @@ -16,19 +17,27 @@ static void Main(string[] args) } + /// Represents the module configuration. public class ModuleConfiguration : DataSourceConfiguration { + /// Gets or sets the plc address. public string PlcAddress { get; set; } } + /// Represents the data source module. public class DataSourceModule : MTConnectInputAgentModule { + /// The configuration type id. public const string ConfigurationTypeId = "datasource"; // This must match the module section in the 'agent.config.yaml' file + /// The default id. public const string DefaultId = "DataSource Module"; // The ID is mainly just used for logging. private readonly ModuleConfiguration _configuration; + /// Initialises a new instance of the data source module type. + /// The agent. + /// The configuration. public DataSourceModule(IMTConnectAgentBroker agent, object configuration) : base(agent) { Id = DefaultId; @@ -38,6 +47,8 @@ public DataSourceModule(IMTConnectAgentBroker agent, object configuration) : bas } + /// Runs the on add device operation. + /// The result of the operation. protected override IDevice OnAddDevice() { var device = new Device(); @@ -52,6 +63,7 @@ protected override IDevice OnAddDevice() } + /// Runs the on read operation. protected override void OnRead() { Log(MTConnect.Logging.MTConnectLogLevel.Information, $"Read PLC Data from ({_configuration.PlcAddress})"); From 6b7da351ab5804b6b576352403a6c6309f38a5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:24:02 +0200 Subject: [PATCH 08/29] docs(json-cppagent-tests): author XML doc comments on test surface --- .../JsonAssetsHeaderSchemaVersionTests.cs | 8 ++++++++ .../Assets/JsonAssetsHeaderValidationTests.cs | 3 +++ ...ppAgentHeaderFieldsRegressionGuardTests.cs | 4 ++++ .../AssetCountWireRepresentationE2ETests.cs | 3 +++ ...figurationPolymorphicAxisRoundTripTests.cs | 11 +++++++++++ ...gurationPolymorphicOriginRoundTripTests.cs | 10 ++++++++++ ...rationPolymorphicRotationRoundTripTests.cs | 9 +++++++++ ...igurationPolymorphicScaleRoundTripTests.cs | 9 +++++++++ ...ionPolymorphicTranslationRoundTripTests.cs | 8 ++++++++ .../JsonComponentEmptyNameOmissionTests.cs | 3 +++ .../JsonComponentNameAttributePinTests.cs | 2 ++ .../JsonCompositionEmptyNameOmissionTests.cs | 3 +++ .../JsonCompositionNameAttributePinTests.cs | 2 ++ .../JsonDataItemEmptyNameOmissionTests.cs | 4 ++++ .../JsonDataItemNameAttributePinTests.cs | 2 ++ .../JsonDataItemPropertyCasingTests.cs | 4 ++++ ...DataItemRelationshipCategorizationTests.cs | 3 +++ .../Devices/JsonDataItemSourceGuardTests.cs | 1 + .../JsonDevicesHeaderSchemaVersionTests.cs | 8 ++++++++ .../JsonDevicesHeaderValidationTests.cs | 3 +++ ...cesResponseDocumentNameOmissionE2ETests.cs | 1 + .../JsonMTConnectDevicesSchemaVersionTests.cs | 2 ++ .../E2E/SampleValueWireFormatE2ETests.cs | 6 ++++++ .../JsonMqttResponseDocumentFormatterTests.cs | 10 ++++++++++ .../JsonRuntimeTypeRoundTripTests.cs | 8 ++++++++ .../JsonHeaderSchemaVersionXmlDocTests.cs | 8 +++++--- .../JsonHeaderWireShapeE2ETests.cs | 6 ++++++ .../JsonHeaderWireShapeMatrixTests.cs | 3 +++ .../Issue128_HardcodedLiteralGuardTests.cs | 2 ++ .../Issue128_SchemaVersionConfiguredTests.cs | 4 ++++ .../Issue129_NumericSampleNumberTokenTests.cs | 8 ++++++++ .../SampleValueWriteStringValueGuardTests.cs | 2 ++ .../SchemaVersionFieldsCoexistTests.cs | 8 ++++++++ .../SanityTests.cs | 2 ++ .../Streams/JsonConditionsArrayShapeTests.cs | 19 +++++++++++++++++++ .../JsonMTConnectStreamsSchemaVersionTests.cs | 2 ++ .../JsonSampleValueConverterEdgeCaseTests.cs | 9 +++++++++ .../JsonSampleValueNumericTokenTests.cs | 13 +++++++++++++ .../JsonSampleValueToObservationTests.cs | 2 ++ .../JsonStreamsHeaderSchemaVersionTests.cs | 8 ++++++++ .../JsonStreamsHeaderValidationTests.cs | 3 +++ .../TestHelpers/RepoRootLocatorTests.cs | 2 ++ 42 files changed, 225 insertions(+), 3 deletions(-) diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Assets/JsonAssetsHeaderSchemaVersionTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Assets/JsonAssetsHeaderSchemaVersionTests.cs index 24ba4ca0f..480adba5a 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Assets/JsonAssetsHeaderSchemaVersionTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Assets/JsonAssetsHeaderSchemaVersionTests.cs @@ -27,6 +27,8 @@ namespace MTConnect.Tests.JsonCppagent.Assets [Category("ComplianceMatrix")] public class JsonAssetsHeaderSchemaVersionTests { + /// Pins the behaviour expressed by the test name: constructor with source header copies schema version. + /// The schema version. [TestCaseSource(typeof(JsonHeaderWireShapeMatrix), nameof(JsonHeaderWireShapeMatrix.SchemaVersionCases))] public void Constructor_with_source_header_copies_schemaVersion(string schemaVersion) { @@ -44,6 +46,8 @@ public void Constructor_with_source_header_copies_schemaVersion(string schemaVer "JsonAssetsHeader must copy SchemaVersion from the source IMTConnectAssetsHeader."); } + /// Pins the behaviour expressed by the test name: serialized assets header emits schema version property. + /// The schema version. [TestCaseSource(typeof(JsonHeaderWireShapeMatrix), nameof(JsonHeaderWireShapeMatrix.SchemaVersionCases))] public void Serialized_assets_header_emits_schemaVersion_property(string schemaVersion) { @@ -61,6 +65,7 @@ public void Serialized_assets_header_emits_schemaVersion_property(string schemaV Assert.That(v.GetString(), Is.EqualTo(schemaVersion)); } + /// Pins the behaviour expressed by the test name: serialized assets header emits test indicator property. [Test] public void Serialized_assets_header_emits_testIndicator_property() { @@ -78,6 +83,7 @@ public void Serialized_assets_header_emits_testIndicator_property() Assert.That(v.GetBoolean(), Is.False); } + /// Pins the behaviour expressed by the test name: reverse mapping round trips schema version. [Test] public void Reverse_mapping_round_trips_schemaVersion() { @@ -92,6 +98,7 @@ public void Reverse_mapping_round_trips_schemaVersion() "ToAssetsHeader must preserve SchemaVersion through the round trip."); } + /// Pins the behaviour expressed by the test name: constructor with null source does not throw. [Test] public void Constructor_with_null_source_does_not_throw() { @@ -100,6 +107,7 @@ public void Constructor_with_null_source_does_not_throw() Assert.That(jsonHeader.SchemaVersion, Is.Null); } + /// Pins the behaviour expressed by the test name: default constructor leaves schema version unset. [Test] public void Default_constructor_leaves_schemaVersion_unset() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Assets/JsonAssetsHeaderValidationTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Assets/JsonAssetsHeaderValidationTests.cs index 4e3c644d9..99ca6bc5e 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Assets/JsonAssetsHeaderValidationTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Assets/JsonAssetsHeaderValidationTests.cs @@ -25,6 +25,7 @@ namespace MTConnect.Tests.JsonCppagent.Assets [Category("CppAgentHeaderFieldsPresent")] public class JsonAssetsHeaderValidationTests { + /// Pins the behaviour expressed by the test name: constructor with source header copies validation. [Test] public void Constructor_with_source_header_copies_validation() { @@ -43,6 +44,7 @@ public void Constructor_with_source_header_copies_validation() "JsonAssetsHeader must copy Validation from the source IMTConnectAssetsHeader."); } + /// Pins the behaviour expressed by the test name: serialized assets header emits validation property. [Test] public void Serialized_assets_header_emits_validation_property() { @@ -60,6 +62,7 @@ public void Serialized_assets_header_emits_validation_property() Assert.That(v.GetBoolean(), Is.True); } + /// Pins the behaviour expressed by the test name: reverse mapping round trips validation. [Test] public void Reverse_mapping_round_trips_validation() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/CppAgentHeaderFieldsRegressionGuardTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/CppAgentHeaderFieldsRegressionGuardTests.cs index 8a3b55255..1b3f49520 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/CppAgentHeaderFieldsRegressionGuardTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/CppAgentHeaderFieldsRegressionGuardTests.cs @@ -32,6 +32,8 @@ public class CppAgentHeaderFieldsRegressionGuardTests typeof(JsonAssetsHeader), }; + /// Pins the behaviour expressed by the test name: header dto exposes schema version property. + /// The header type. [TestCaseSource(nameof(HeaderDtos))] public void Header_dto_exposes_schemaVersion_property(System.Type headerType) { @@ -50,6 +52,8 @@ public void Header_dto_exposes_schemaVersion_property(System.Type headerType) $"{headerType.Name}.SchemaVersion must serialize as 'schemaVersion'."); } + /// Pins the behaviour expressed by the test name: header dto exposes test indicator property. + /// The header type. [TestCaseSource(nameof(HeaderDtos))] public void Header_dto_exposes_testIndicator_property(System.Type headerType) { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/AssetCountWireRepresentationE2ETests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/AssetCountWireRepresentationE2ETests.cs index 6a365bdeb..c513df7f2 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/AssetCountWireRepresentationE2ETests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/AssetCountWireRepresentationE2ETests.cs @@ -54,6 +54,7 @@ namespace MTConnect.Tests.JsonCppagent.Devices [Category("AssetCountIsDataSet")] public class AssetCountWireRepresentationE2ETests { + /// Pins the behaviour expressed by the test name: probe response emits exactly one a s s e t c o u n t per device with d a t a s e t representation. [Test] public void Probe_response_emits_exactly_one_ASSET_COUNT_per_device_with_DATA_SET_representation() { @@ -133,6 +134,7 @@ public void Probe_response_emits_exactly_one_ASSET_COUNT_per_device_with_DATA_SE } } + /// Pins the behaviour expressed by the test name: probe response for agent device emits exactly one a s s e t c o u n t with d a t a s e t. [Test] public void Probe_response_for_agent_device_emits_exactly_one_ASSET_COUNT_with_DATA_SET() { @@ -180,6 +182,7 @@ public void Probe_response_for_agent_device_emits_exactly_one_ASSET_COUNT_with_D "Agent device ASSET_COUNT representation is not DATA_SET on the wire."); } + /// Pins the behaviour expressed by the test name: probe response string carries no v a l u e representation on any a s s e t c o u n t entry. [Test] public void Probe_response_string_carries_no_VALUE_representation_on_any_ASSET_COUNT_entry() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs index caeb49441..7ccfa0b7e 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs @@ -31,6 +31,7 @@ public class ConfigurationPolymorphicAxisRoundTripTests { // ---------------- positive: simple Axis ---------------- + /// Pins the behaviour expressed by the test name: simple axis serialises as numeric array. [Test] public void Simple_Axis_serialises_as_numeric_array() { @@ -48,6 +49,7 @@ public void Simple_Axis_serialises_as_numeric_array() Assert.That(json, Does.Not.Contain("AxisDataSet")); } + /// Pins the behaviour expressed by the test name: simple axis round trips through numeric array. [Test] public void Simple_Axis_round_trips_through_numeric_array() { @@ -70,6 +72,7 @@ public void Simple_Axis_round_trips_through_numeric_array() // ---------------- positive: AxisDataSet ---------------- + /// Pins the behaviour expressed by the test name: axis data set serialises as flat pascalcase object. [Test] public void AxisDataSet_serialises_as_flat_pascalcase_object() { @@ -87,6 +90,7 @@ public void AxisDataSet_serialises_as_flat_pascalcase_object() Assert.That(json, Does.Not.Contain("\"Axis\":[")); } + /// Pins the behaviour expressed by the test name: axis data set round trips through flat object. [Test] public void AxisDataSet_round_trips_through_flat_object() { @@ -105,6 +109,7 @@ public void AxisDataSet_round_trips_through_flat_object() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: both array and dataset present data set wins. [Test] public void Both_array_and_dataset_present_DataSet_wins() { @@ -119,6 +124,7 @@ public void Both_array_and_dataset_present_DataSet_wins() Assert.That(((IAxisDataSet)motion.Axis).X, Is.EqualTo(9.0)); } + /// Pins the behaviour expressed by the test name: null axis property emits neither field. [Test] public void Null_axis_property_emits_neither_field() { @@ -136,6 +142,7 @@ public void Null_axis_property_emits_neither_field() Assert.That(json, Does.Not.Contain("AxisDataSet")); } + /// Pins the behaviour expressed by the test name: json axis data set default constructor yields zero components. [Test] public void JsonAxisDataSet_default_constructor_yields_zero_components() { @@ -147,6 +154,7 @@ public void JsonAxisDataSet_default_constructor_yields_zero_components() Assert.That(ds.Z, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: json axis data set ctor with null input keeps default values. [Test] public void JsonAxisDataSet_ctor_with_null_input_keeps_default_values() { @@ -154,6 +162,7 @@ public void JsonAxisDataSet_ctor_with_null_input_keeps_default_values() Assert.That(ja.X, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: null motion passed to ctor keeps default values. [Test] public void Null_motion_passed_to_ctor_keeps_default_values() { @@ -162,6 +171,7 @@ public void Null_motion_passed_to_ctor_keeps_default_values() Assert.That(jm.AxisDataSet, Is.Null); } + /// Pins the behaviour expressed by the test name: empty array axis deserialises to null simple axis. [Test] public void Empty_array_axis_deserialises_to_null_simple_axis() { @@ -177,6 +187,7 @@ public void Empty_array_axis_deserialises_to_null_simple_axis() Assert.That(motion.Axis, Is.Null); } + /// Pins the behaviour expressed by the test name: numeric array round trip normalises invariant culture. [Test] public void Numeric_array_round_trip_normalises_invariant_culture() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs index d83753a3c..ebf847d94 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs @@ -29,6 +29,7 @@ public class ConfigurationPolymorphicOriginRoundTripTests { // ---------------- positive: Motion + simple Origin ---------------- + /// Pins the behaviour expressed by the test name: simple origin serialises as numeric array on motion. [Test] public void Simple_Origin_serialises_as_numeric_array_on_Motion() { @@ -46,6 +47,7 @@ public void Simple_Origin_serialises_as_numeric_array_on_Motion() Assert.That(json, Does.Not.Contain("OriginDataSet")); } + /// Pins the behaviour expressed by the test name: simple origin round trips through numeric array on motion. [Test] public void Simple_Origin_round_trips_through_numeric_array_on_Motion() { @@ -67,6 +69,7 @@ public void Simple_Origin_round_trips_through_numeric_array_on_Motion() // ---------------- positive: Motion + OriginDataSet ---------------- + /// Pins the behaviour expressed by the test name: origin data set serialises as flat pascalcase object on motion. [Test] public void OriginDataSet_serialises_as_flat_pascalcase_object_on_Motion() { @@ -83,6 +86,7 @@ public void OriginDataSet_serialises_as_flat_pascalcase_object_on_Motion() Assert.That(json, Does.Contain("\"OriginDataSet\":{\"X\":\"1\",\"Y\":\"2\",\"Z\":\"3\"}")); } + /// Pins the behaviour expressed by the test name: origin data set deserialises to i origin data set on motion. [Test] public void OriginDataSet_deserialises_to_IOriginDataSet_on_Motion() { @@ -101,6 +105,7 @@ public void OriginDataSet_deserialises_to_IOriginDataSet_on_Motion() // ---------------- positive: CoordinateSystem ---------------- + /// Pins the behaviour expressed by the test name: simple origin round trips on coordinate system. [Test] public void Simple_Origin_round_trips_on_CoordinateSystem() { @@ -120,6 +125,7 @@ public void Simple_Origin_round_trips_on_CoordinateSystem() Assert.That(((IOrigin)output.Origin).Value, Is.EqualTo("10 20 30")); } + /// Pins the behaviour expressed by the test name: origin data set round trips on coordinate system. [Test] public void OriginDataSet_round_trips_on_CoordinateSystem() { @@ -140,6 +146,7 @@ public void OriginDataSet_round_trips_on_CoordinateSystem() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: both origin and origin data set present data set wins. [Test] public void Both_Origin_and_OriginDataSet_present_DataSet_wins() { @@ -154,6 +161,7 @@ public void Both_Origin_and_OriginDataSet_present_DataSet_wins() Assert.That(((IOriginDataSet)motion.Origin).X, Is.EqualTo("9")); } + /// Pins the behaviour expressed by the test name: json origin data set default constructor yields null components. [Test] public void JsonOriginDataSet_default_constructor_yields_null_components() { @@ -163,6 +171,7 @@ public void JsonOriginDataSet_default_constructor_yields_null_components() Assert.That(ds.X, Is.Null); } + /// Pins the behaviour expressed by the test name: json origin data set ctor with null input keeps default values. [Test] public void JsonOriginDataSet_ctor_with_null_input_keeps_default_values() { @@ -170,6 +179,7 @@ public void JsonOriginDataSet_ctor_with_null_input_keeps_default_values() Assert.That(jo.X, Is.Null); } + /// Pins the behaviour expressed by the test name: null coordinate system passed to ctor keeps default values. [Test] public void Null_coordinateSystem_passed_to_ctor_keeps_default_values() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs index 15bac1f5f..dc544c9fb 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs @@ -29,6 +29,7 @@ public class ConfigurationPolymorphicRotationRoundTripTests { // ---------------- positive: simple Rotation ---------------- + /// Pins the behaviour expressed by the test name: simple rotation serialises as numeric array. [Test] public void Simple_Rotation_serialises_as_numeric_array() { @@ -43,6 +44,7 @@ public void Simple_Rotation_serialises_as_numeric_array() Assert.That(json, Does.Not.Contain("RotationDataSet")); } + /// Pins the behaviour expressed by the test name: simple rotation deserialises to i rotation. [Test] public void Simple_Rotation_deserialises_to_IRotation() { @@ -57,6 +59,7 @@ public void Simple_Rotation_deserialises_to_IRotation() // ---------------- positive: RotationDataSet ---------------- + /// Pins the behaviour expressed by the test name: rotation data set serialises as flat pascalcase object. [Test] public void RotationDataSet_serialises_as_flat_pascalcase_object() { @@ -70,6 +73,7 @@ public void RotationDataSet_serialises_as_flat_pascalcase_object() Assert.That(json, Does.Contain("\"RotationDataSet\":{\"A\":\"10\",\"B\":\"20\",\"C\":\"30\"}")); } + /// Pins the behaviour expressed by the test name: rotation data set deserialises to i rotation data set. [Test] public void RotationDataSet_deserialises_to_IRotationDataSet() { @@ -87,6 +91,7 @@ public void RotationDataSet_deserialises_to_IRotationDataSet() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: both rotation and rotation data set present data set wins. [Test] public void Both_Rotation_and_RotationDataSet_present_DataSet_wins() { @@ -100,6 +105,7 @@ public void Both_Rotation_and_RotationDataSet_present_DataSet_wins() Assert.That(((IRotationDataSet)t.Rotation).A, Is.EqualTo("9")); } + /// Pins the behaviour expressed by the test name: json rotation data set default constructor yields null components. [Test] public void JsonRotationDataSet_default_constructor_yields_null_components() { @@ -109,6 +115,7 @@ public void JsonRotationDataSet_default_constructor_yields_null_components() Assert.That(ds.A, Is.Null); } + /// Pins the behaviour expressed by the test name: json rotation data set ctor with null input keeps default values. [Test] public void JsonRotationDataSet_ctor_with_null_input_keeps_default_values() { @@ -116,6 +123,7 @@ public void JsonRotationDataSet_ctor_with_null_input_keeps_default_values() Assert.That(jr.A, Is.Null); } + /// Pins the behaviour expressed by the test name: null transformation passed to ctor keeps default values. [Test] public void Null_transformation_passed_to_ctor_keeps_default_values() { @@ -124,6 +132,7 @@ public void Null_transformation_passed_to_ctor_keeps_default_values() Assert.That(jt.RotationDataSet, Is.Null); } + /// Pins the behaviour expressed by the test name: null rotation property emits no rotation field. [Test] public void Null_rotation_property_emits_no_rotation_field() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs index 5eb0364fa..3a6ea1bd9 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs @@ -28,6 +28,7 @@ public class ConfigurationPolymorphicScaleRoundTripTests { // ---------------- positive: simple Scale ---------------- + /// Pins the behaviour expressed by the test name: simple scale serialises as numeric array. [Test] public void Simple_Scale_serialises_as_numeric_array() { @@ -44,6 +45,7 @@ public void Simple_Scale_serialises_as_numeric_array() Assert.That(json, Does.Not.Contain("ScaleDataSet")); } + /// Pins the behaviour expressed by the test name: simple scale deserialises to i scale. [Test] public void Simple_Scale_deserialises_to_IScale() { @@ -59,6 +61,7 @@ public void Simple_Scale_deserialises_to_IScale() // ---------------- positive: ScaleDataSet ---------------- + /// Pins the behaviour expressed by the test name: scale data set serialises as flat pascalcase object. [Test] public void ScaleDataSet_serialises_as_flat_pascalcase_object() { @@ -74,6 +77,7 @@ public void ScaleDataSet_serialises_as_flat_pascalcase_object() Assert.That(json, Does.Contain("\"ScaleDataSet\":{\"X\":1.5,\"Y\":2.5,\"Z\":3.5}")); } + /// Pins the behaviour expressed by the test name: scale data set deserialises to i scale data set. [Test] public void ScaleDataSet_deserialises_to_IScaleDataSet() { @@ -92,6 +96,7 @@ public void ScaleDataSet_deserialises_to_IScaleDataSet() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: both scale and scale data set present data set wins. [Test] public void Both_Scale_and_ScaleDataSet_present_DataSet_wins() { @@ -106,6 +111,7 @@ public void Both_Scale_and_ScaleDataSet_present_DataSet_wins() Assert.That(((IScaleDataSet)sm.Scale).X, Is.EqualTo(9.0)); } + /// Pins the behaviour expressed by the test name: null scale property emits neither field. [Test] public void Null_scale_property_emits_neither_field() { @@ -122,6 +128,7 @@ public void Null_scale_property_emits_neither_field() Assert.That(json, Does.Not.Contain("ScaleDataSet")); } + /// Pins the behaviour expressed by the test name: json scale data set default constructor yields zero components. [Test] public void JsonScaleDataSet_default_constructor_yields_zero_components() { @@ -131,6 +138,7 @@ public void JsonScaleDataSet_default_constructor_yields_zero_components() Assert.That(ds.X, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: json scale data set ctor with null input keeps default values. [Test] public void JsonScaleDataSet_ctor_with_null_input_keeps_default_values() { @@ -138,6 +146,7 @@ public void JsonScaleDataSet_ctor_with_null_input_keeps_default_values() Assert.That(js.X, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: null solid model passed to ctor keeps default values. [Test] public void Null_solidModel_passed_to_ctor_keeps_default_values() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs index cdcc73369..5a104cff5 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs @@ -29,6 +29,7 @@ public class ConfigurationPolymorphicTranslationRoundTripTests { // ---------------- positive: simple Translation ---------------- + /// Pins the behaviour expressed by the test name: simple translation serialises as numeric array. [Test] public void Simple_Translation_serialises_as_numeric_array() { @@ -43,6 +44,7 @@ public void Simple_Translation_serialises_as_numeric_array() Assert.That(json, Does.Not.Contain("TranslationDataSet")); } + /// Pins the behaviour expressed by the test name: simple translation deserialises to i translation. [Test] public void Simple_Translation_deserialises_to_ITranslation() { @@ -57,6 +59,7 @@ public void Simple_Translation_deserialises_to_ITranslation() // ---------------- positive: TranslationDataSet ---------------- + /// Pins the behaviour expressed by the test name: translation data set serialises as flat pascalcase object. [Test] public void TranslationDataSet_serialises_as_flat_pascalcase_object() { @@ -70,6 +73,7 @@ public void TranslationDataSet_serialises_as_flat_pascalcase_object() Assert.That(json, Does.Contain("\"TranslationDataSet\":{\"X\":\"1\",\"Y\":\"2\",\"Z\":\"3\"}")); } + /// Pins the behaviour expressed by the test name: translation data set deserialises to i translation data set. [Test] public void TranslationDataSet_deserialises_to_ITranslationDataSet() { @@ -87,6 +91,7 @@ public void TranslationDataSet_deserialises_to_ITranslationDataSet() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: both translation and translation data set present data set wins. [Test] public void Both_Translation_and_TranslationDataSet_present_DataSet_wins() { @@ -100,6 +105,7 @@ public void Both_Translation_and_TranslationDataSet_present_DataSet_wins() Assert.That(((ITranslationDataSet)t.Translation).X, Is.EqualTo("9")); } + /// Pins the behaviour expressed by the test name: json translation data set default constructor yields null components. [Test] public void JsonTranslationDataSet_default_constructor_yields_null_components() { @@ -109,6 +115,7 @@ public void JsonTranslationDataSet_default_constructor_yields_null_components() Assert.That(ds.X, Is.Null); } + /// Pins the behaviour expressed by the test name: json translation data set ctor with null input keeps default values. [Test] public void JsonTranslationDataSet_ctor_with_null_input_keeps_default_values() { @@ -116,6 +123,7 @@ public void JsonTranslationDataSet_ctor_with_null_input_keeps_default_values() Assert.That(jt.X, Is.Null); } + /// Pins the behaviour expressed by the test name: both translation and rotation data set round trip independently. [Test] public void Both_Translation_and_Rotation_DataSet_round_trip_independently() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonComponentEmptyNameOmissionTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonComponentEmptyNameOmissionTests.cs index 1fe8c1bd2..17f5793c3 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonComponentEmptyNameOmissionTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonComponentEmptyNameOmissionTests.cs @@ -26,6 +26,7 @@ namespace MTConnect.Tests.JsonCppagent.Devices [Category("NameAttributeOmissionWhenUnsetOrEmpty")] public class JsonComponentEmptyNameOmissionTests { + /// Pins the behaviour expressed by the test name: constructor with null name source does not serialize name key. [Test] public void Constructor_with_null_Name_source_does_not_serialize_name_key() { @@ -36,6 +37,7 @@ public void Constructor_with_null_Name_source_does_not_serialize_name_key() "JSON-cppagent Probe Component must omit 'name' when source Name is null"); } + /// Pins the behaviour expressed by the test name: constructor with empty name source does not serialize name key. [Test] public void Constructor_with_empty_Name_source_does_not_serialize_name_key() { @@ -46,6 +48,7 @@ public void Constructor_with_empty_Name_source_does_not_serialize_name_key() "JSON-cppagent Probe Component must omit 'name' when source Name is empty"); } + /// Pins the behaviour expressed by the test name: constructor with explicit name source serializes name key. [Test] public void Constructor_with_explicit_Name_source_serializes_name_key() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonComponentNameAttributePinTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonComponentNameAttributePinTests.cs index 973194141..b58665dca 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonComponentNameAttributePinTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonComponentNameAttributePinTests.cs @@ -28,6 +28,7 @@ namespace MTConnect.Tests.JsonCppagent.Devices [Category("NameAttributeOmissionWhenUnsetOrEmpty")] public class JsonComponentNameAttributePinTests { + /// Pins the behaviour expressed by the test name: name property carries json ignore when writing null attribute. [Test] public void Name_property_carries_JsonIgnore_WhenWritingNull_attribute() { @@ -39,6 +40,7 @@ public void Name_property_carries_JsonIgnore_WhenWritingNull_attribute() "JsonComponent.Name [JsonIgnore] condition must be WhenWritingNull."); } + /// Pins the behaviour expressed by the test name: raw system text json serialise omits name when null. [Test] public void Raw_System_Text_Json_serialise_omits_name_when_null() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonCompositionEmptyNameOmissionTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonCompositionEmptyNameOmissionTests.cs index 186698540..0cae99760 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonCompositionEmptyNameOmissionTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonCompositionEmptyNameOmissionTests.cs @@ -27,6 +27,7 @@ namespace MTConnect.Tests.JsonCppagent.Devices [Category("NameAttributeOmissionWhenUnsetOrEmpty")] public class JsonCompositionEmptyNameOmissionTests { + /// Pins the behaviour expressed by the test name: constructor with null name source does not serialize name key. [Test] public void Constructor_with_null_Name_source_does_not_serialize_name_key() { @@ -37,6 +38,7 @@ public void Constructor_with_null_Name_source_does_not_serialize_name_key() "JSON-cppagent Probe Composition must omit 'name' when source Name is null"); } + /// Pins the behaviour expressed by the test name: constructor with empty name source does not serialize name key. [Test] public void Constructor_with_empty_Name_source_does_not_serialize_name_key() { @@ -47,6 +49,7 @@ public void Constructor_with_empty_Name_source_does_not_serialize_name_key() "JSON-cppagent Probe Composition must omit 'name' when source Name is empty"); } + /// Pins the behaviour expressed by the test name: constructor with explicit name source serializes name key. [Test] public void Constructor_with_explicit_Name_source_serializes_name_key() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonCompositionNameAttributePinTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonCompositionNameAttributePinTests.cs index 1aa8f5077..510386f5d 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonCompositionNameAttributePinTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonCompositionNameAttributePinTests.cs @@ -28,6 +28,7 @@ namespace MTConnect.Tests.JsonCppagent.Devices [Category("NameAttributeOmissionWhenUnsetOrEmpty")] public class JsonCompositionNameAttributePinTests { + /// Pins the behaviour expressed by the test name: name property carries json ignore when writing null attribute. [Test] public void Name_property_carries_JsonIgnore_WhenWritingNull_attribute() { @@ -39,6 +40,7 @@ public void Name_property_carries_JsonIgnore_WhenWritingNull_attribute() "JsonComposition.Name [JsonIgnore] condition must be WhenWritingNull."); } + /// Pins the behaviour expressed by the test name: raw system text json serialise omits name when null. [Test] public void Raw_System_Text_Json_serialise_omits_name_when_null() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemEmptyNameOmissionTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemEmptyNameOmissionTests.cs index 29d0ff3ed..850fa407c 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemEmptyNameOmissionTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemEmptyNameOmissionTests.cs @@ -26,6 +26,7 @@ namespace MTConnect.Tests.JsonCppagent.Devices [Category("NameAttributeOmissionWhenUnsetOrEmpty")] public class JsonDataItemEmptyNameOmissionTests { + /// Pins the behaviour expressed by the test name: constructor with null name source does not serialize name key. [Test] public void Constructor_with_null_Name_source_does_not_serialize_name_key() { @@ -44,6 +45,7 @@ public void Constructor_with_null_Name_source_does_not_serialize_name_key() "JSON-cppagent Probe DataItem must omit 'name' when source Name is null"); } + /// Pins the behaviour expressed by the test name: constructor with empty name source does not serialize name key. [Test] public void Constructor_with_empty_Name_source_does_not_serialize_name_key() { @@ -62,6 +64,7 @@ public void Constructor_with_empty_Name_source_does_not_serialize_name_key() "JSON-cppagent Probe DataItem must omit 'name' when source Name is empty"); } + /// Pins the behaviour expressed by the test name: constructor with explicit name source serializes name key. [Test] public void Constructor_with_explicit_Name_source_serializes_name_key() { @@ -81,6 +84,7 @@ public void Constructor_with_explicit_Name_source_serializes_name_key() Assert.That(nameElement.GetString(), Is.EqualTo("temp")); } + /// Pins the behaviour expressed by the test name: constructor with typed data item unset name does not serialize name key. [Test] public void Constructor_with_typed_DataItem_unset_Name_does_not_serialize_name_key() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemNameAttributePinTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemNameAttributePinTests.cs index faa317d29..9bd423d8d 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemNameAttributePinTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemNameAttributePinTests.cs @@ -34,6 +34,7 @@ namespace MTConnect.Tests.JsonCppagent.Devices [Category("NameAttributeOmissionWhenUnsetOrEmpty")] public class JsonDataItemNameAttributePinTests { + /// Pins the behaviour expressed by the test name: name property carries json ignore when writing null attribute. [Test] public void Name_property_carries_JsonIgnore_WhenWritingNull_attribute() { @@ -45,6 +46,7 @@ public void Name_property_carries_JsonIgnore_WhenWritingNull_attribute() "JsonDataItem.Name [JsonIgnore] condition must be WhenWritingNull."); } + /// Pins the behaviour expressed by the test name: raw system text json serialise omits name when null. [Test] public void Raw_System_Text_Json_serialise_omits_name_when_null() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemPropertyCasingTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemPropertyCasingTests.cs index 606b0cd4e..d687e492a 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemPropertyCasingTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemPropertyCasingTests.cs @@ -50,6 +50,8 @@ private static string GetJsonName(string clrPropertyName) return attribute!.Name; } + /// Pins the behaviour expressed by the test name: complex object property uses pascal case json key. + /// The entry. [TestCaseSource(nameof(PascalCaseObjects))] public void Complex_object_property_uses_PascalCase_json_key((string Clr, string Json) entry) { @@ -57,6 +59,8 @@ public void Complex_object_property_uses_PascalCase_json_key((string Clr, string "Complex object members on JsonDataItem must remain PascalCase to match the cppagent JSON wire shape."); } + /// Pins the behaviour expressed by the test name: scalar attribute property uses camel case json key. + /// The entry. [TestCaseSource(nameof(CamelCaseScalars))] public void Scalar_attribute_property_uses_camelCase_json_key((string Clr, string Json) entry) { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemRelationshipCategorizationTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemRelationshipCategorizationTests.cs index 72feb86d1..51ae98dcd 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemRelationshipCategorizationTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemRelationshipCategorizationTests.cs @@ -19,6 +19,7 @@ namespace MTConnect.Tests.JsonCppagent.Devices [TestFixture] public class JsonDataItemRelationshipCategorizationTests { + /// Pins the behaviour expressed by the test name: both abstract relationship kinds route to their matching container bucket. [Test] public void Both_abstract_relationship_kinds_route_to_their_matching_container_bucket() { @@ -44,6 +45,7 @@ public void Both_abstract_relationship_kinds_route_to_their_matching_container_b Assert.That(json.Relationships.SpecificationRelationships, Has.Count.EqualTo(1)); } + /// Pins the behaviour expressed by the test name: empty relationships collection leaves container null. [Test] public void Empty_relationships_collection_leaves_container_null() { @@ -60,6 +62,7 @@ public void Empty_relationships_collection_leaves_container_null() "JsonDataItem must skip the relationship container when the source has none."); } + /// Pins the behaviour expressed by the test name: multiple relationships of same kind aggregate in their bucket. [Test] public void Multiple_relationships_of_same_kind_aggregate_in_their_bucket() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemSourceGuardTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemSourceGuardTests.cs index fd0844a88..8c36391de 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemSourceGuardTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDataItemSourceGuardTests.cs @@ -29,6 +29,7 @@ public class JsonDataItemSourceGuardTests "libraries/MTConnect.NET-JSON/Devices/JsonDataItem.cs" }; + /// Pins the behaviour expressed by the test name: json data item constructors must not copy name unconditionally. [Test] public void JsonDataItem_constructors_must_not_copy_Name_unconditionally() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesHeaderSchemaVersionTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesHeaderSchemaVersionTests.cs index 988603a3e..3a4edd437 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesHeaderSchemaVersionTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesHeaderSchemaVersionTests.cs @@ -27,6 +27,8 @@ namespace MTConnect.Tests.JsonCppagent.Devices [Category("ComplianceMatrix")] public class JsonDevicesHeaderSchemaVersionTests { + /// Pins the behaviour expressed by the test name: constructor with source header copies schema version. + /// The schema version. [TestCaseSource(typeof(JsonHeaderWireShapeMatrix), nameof(JsonHeaderWireShapeMatrix.SchemaVersionCases))] public void Constructor_with_source_header_copies_schemaVersion(string schemaVersion) { @@ -44,6 +46,8 @@ public void Constructor_with_source_header_copies_schemaVersion(string schemaVer "JsonDevicesHeader must copy SchemaVersion from the source IMTConnectDevicesHeader."); } + /// Pins the behaviour expressed by the test name: serialized devices header emits schema version property. + /// The schema version. [TestCaseSource(typeof(JsonHeaderWireShapeMatrix), nameof(JsonHeaderWireShapeMatrix.SchemaVersionCases))] public void Serialized_devices_header_emits_schemaVersion_property(string schemaVersion) { @@ -61,6 +65,7 @@ public void Serialized_devices_header_emits_schemaVersion_property(string schema Assert.That(v.GetString(), Is.EqualTo(schemaVersion)); } + /// Pins the behaviour expressed by the test name: serialized devices header emits test indicator property. [Test] public void Serialized_devices_header_emits_testIndicator_property() { @@ -78,6 +83,7 @@ public void Serialized_devices_header_emits_testIndicator_property() Assert.That(v.GetBoolean(), Is.False); } + /// Pins the behaviour expressed by the test name: reverse mapping round trips schema version. [Test] public void Reverse_mapping_round_trips_schemaVersion() { @@ -92,6 +98,7 @@ public void Reverse_mapping_round_trips_schemaVersion() "ToDevicesHeader must preserve SchemaVersion through the round trip."); } + /// Pins the behaviour expressed by the test name: constructor with null source does not throw. [Test] public void Constructor_with_null_source_does_not_throw() { @@ -100,6 +107,7 @@ public void Constructor_with_null_source_does_not_throw() Assert.That(jsonHeader.SchemaVersion, Is.Null); } + /// Pins the behaviour expressed by the test name: default constructor leaves schema version unset. [Test] public void Default_constructor_leaves_schemaVersion_unset() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesHeaderValidationTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesHeaderValidationTests.cs index bf0c1d8a5..fb43b16a0 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesHeaderValidationTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesHeaderValidationTests.cs @@ -25,6 +25,7 @@ namespace MTConnect.Tests.JsonCppagent.Devices [Category("CppAgentHeaderFieldsPresent")] public class JsonDevicesHeaderValidationTests { + /// Pins the behaviour expressed by the test name: constructor with source header copies validation. [Test] public void Constructor_with_source_header_copies_validation() { @@ -43,6 +44,7 @@ public void Constructor_with_source_header_copies_validation() "JsonDevicesHeader must copy Validation from the source IMTConnectDevicesHeader."); } + /// Pins the behaviour expressed by the test name: serialized devices header emits validation property. [Test] public void Serialized_devices_header_emits_validation_property() { @@ -60,6 +62,7 @@ public void Serialized_devices_header_emits_validation_property() Assert.That(v.GetBoolean(), Is.True); } + /// Pins the behaviour expressed by the test name: reverse mapping round trips validation. [Test] public void Reverse_mapping_round_trips_validation() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesResponseDocumentNameOmissionE2ETests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesResponseDocumentNameOmissionE2ETests.cs index 9a74e35ad..798d52be2 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesResponseDocumentNameOmissionE2ETests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonDevicesResponseDocumentNameOmissionE2ETests.cs @@ -29,6 +29,7 @@ namespace MTConnect.Tests.JsonCppagent.Devices [TestFixture] public class JsonDevicesResponseDocumentNameOmissionE2ETests { + /// Pins the behaviour expressed by the test name: probe response omits name on unnamed dataitems keeps it on named. [Test] public void Probe_response_omits_name_on_unnamed_dataitems_keeps_it_on_named() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonMTConnectDevicesSchemaVersionTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonMTConnectDevicesSchemaVersionTests.cs index 61eb0d636..98c2cc6b4 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonMTConnectDevicesSchemaVersionTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Devices/JsonMTConnectDevicesSchemaVersionTests.cs @@ -20,6 +20,8 @@ namespace MTConnect.NET_JSON_cppagent_Tests.Devices [Category("SchemaVersionFromConfiguration")] public class JsonMTConnectDevicesSchemaVersionTests { + /// Pins the behaviour expressed by the test name: devices envelope schema version equals configured release. + /// The configured. [TestCaseSource(typeof(VersionMatrix), nameof(VersionMatrix.All))] public void Devices_envelope_schemaVersion_equals_configured_release(Version configured) { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/E2E/SampleValueWireFormatE2ETests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/E2E/SampleValueWireFormatE2ETests.cs index f60c906c2..d8a966013 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/E2E/SampleValueWireFormatE2ETests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/E2E/SampleValueWireFormatE2ETests.cs @@ -46,6 +46,9 @@ private static JsonElement Serialize(IObservation observation) return doc.RootElement.GetProperty("value").Clone(); } + /// Pins the behaviour expressed by the test name: numeric observation serializes as json number token. + /// The data item id. + /// The result. [TestCase("temp", "863.7060")] [TestCase("temp", "0.0001")] [TestCase("rotary-velocity", "12345")] @@ -59,6 +62,7 @@ public void Numeric_observation_serializes_as_json_number_token(string dataItemI $"got {token.ValueKind} instead."); } + /// Pins the behaviour expressed by the test name: unavailable observation serializes as json string token. [Test] public void Unavailable_observation_serializes_as_json_string_token() { @@ -68,6 +72,7 @@ public void Unavailable_observation_serializes_as_json_string_token() Assert.That(token.GetString(), Is.EqualTo("UNAVAILABLE")); } + /// Pins the behaviour expressed by the test name: three space observation preserves string token. [Test] public void Three_space_observation_preserves_string_token() { @@ -80,6 +85,7 @@ public void Three_space_observation_preserves_string_token() Assert.That(token.GetString(), Is.EqualTo("1.5 -2.5 3.5")); } + /// Pins the behaviour expressed by the test name: numeric value round trips to observation. [Test] public void Numeric_value_round_trips_to_observation() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Formatters/JsonMqttResponseDocumentFormatterTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Formatters/JsonMqttResponseDocumentFormatterTests.cs index bc39b72d1..d3a216fb5 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Formatters/JsonMqttResponseDocumentFormatterTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Formatters/JsonMqttResponseDocumentFormatterTests.cs @@ -128,6 +128,7 @@ private static JsonElement GetRoot(FormatWriteResult result) } + /// Pins the behaviour expressed by the test name: mqtt probe formatter emits full envelope with agent and device keys. [Test] public void MqttProbeFormatter_emits_full_envelope_with_Agent_and_Device_keys() { @@ -172,6 +173,7 @@ public void MqttProbeFormatter_emits_full_envelope_with_Agent_and_Device_keys() "Devices.Device must contain both source Device entries; none may be dropped."); } + /// Pins the behaviour expressed by the test name: mqtt probe formatter single device only emits device array only no agent key. [Test] public void MqttProbeFormatter_single_device_only_emits_Device_array_only_no_Agent_key() { @@ -203,6 +205,7 @@ public void MqttProbeFormatter_single_device_only_emits_Device_array_only_no_Age } } + /// Pins the behaviour expressed by the test name: mqtt probe formatter agent only emits agent array only no device key. [Test] public void MqttProbeFormatter_Agent_only_emits_Agent_array_only_no_Device_key() { @@ -232,6 +235,7 @@ public void MqttProbeFormatter_Agent_only_emits_Agent_array_only_no_Device_key() } } + /// Pins the behaviour expressed by the test name: mqtt probe formatter preserves device order within each array. [Test] public void MqttProbeFormatter_preserves_device_order_within_each_array() { @@ -261,6 +265,7 @@ public void MqttProbeFormatter_preserves_device_order_within_each_array() "Devices.Device[2] must be the third source device."); } + /// Pins the behaviour expressed by the test name: mqtt probe formatter emits header and m t connect devices wrapper. [Test] public void MqttProbeFormatter_emits_Header_and_MTConnectDevices_wrapper() { @@ -290,6 +295,7 @@ public void MqttProbeFormatter_emits_Header_and_MTConnectDevices_wrapper() Assert.That(devicesNode.ValueKind, Is.EqualTo(JsonValueKind.Object)); } + /// Pins the behaviour expressed by the test name: mqtt probe formatter empty devices returns error result. [Test] public void MqttProbeFormatter_empty_devices_returns_error_result() { @@ -306,6 +312,7 @@ public void MqttProbeFormatter_empty_devices_returns_error_result() "Empty Devices must yield FormatWriteResult.Error(), not a successful empty envelope."); } + /// Pins the behaviour expressed by the test name: mqtt probe formatter indented output option is respected. [Test] public void MqttProbeFormatter_indented_output_option_is_respected() { @@ -341,6 +348,7 @@ public void MqttProbeFormatter_indented_output_option_is_respected() // and Type-tag intact. // --------------------------------------------------------------- + /// Pins the behaviour expressed by the test name: mqtt probe formatter round trip envelope preserves multi device shape. [Test] public void MqttProbeFormatter_round_trip_envelope_preserves_multi_device_shape() { @@ -384,6 +392,7 @@ public void MqttProbeFormatter_round_trip_envelope_preserves_multi_device_shape( } } + /// Pins the behaviour expressed by the test name: mqtt probe formatter round trip envelope preserves agent device typing. [Test] public void MqttProbeFormatter_round_trip_envelope_preserves_Agent_Device_typing() { @@ -439,6 +448,7 @@ public void MqttProbeFormatter_round_trip_envelope_preserves_Agent_Device_typing + "breaks the discriminator round-trip."); } + /// Pins the behaviour expressed by the test name: mqtt probe formatter preserves agent name case in envelope output. [Test] public void MqttProbeFormatter_preserves_Agent_name_case_in_envelope_output() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Formatters/JsonRuntimeTypeRoundTripTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Formatters/JsonRuntimeTypeRoundTripTests.cs index 360a4a48a..af4fc78e2 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Formatters/JsonRuntimeTypeRoundTripTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Formatters/JsonRuntimeTypeRoundTripTests.cs @@ -31,6 +31,7 @@ public class JsonRuntimeTypeRoundTripTests { // ---- JsonComponent.ToComponent ---------------------------------- + /// Pins the behaviour expressed by the test name: json component to component preserves runtime type for typed subclass. [Test] public void JsonComponent_ToComponent_preserves_runtime_type_for_typed_subclass() { @@ -64,6 +65,7 @@ public void JsonComponent_ToComponent_preserves_runtime_type_for_typed_subclass( Assert.That(roundTripped.Uuid, Is.EqualTo("uuid-axes-1")); } + /// Pins the behaviour expressed by the test name: json component to component preserves runtime type for controller subclass. [Test] public void JsonComponent_ToComponent_preserves_runtime_type_for_Controller_subclass() { @@ -87,6 +89,7 @@ public void JsonComponent_ToComponent_preserves_runtime_type_for_Controller_subc // ---- JsonComposition.ToComposition ------------------------------ + /// Pins the behaviour expressed by the test name: json composition to composition preserves runtime type for typed subclass. [Test] public void JsonComposition_ToComposition_preserves_runtime_type_for_typed_subclass() { @@ -118,6 +121,7 @@ public void JsonComposition_ToComposition_preserves_runtime_type_for_typed_subcl // ---- JsonCompositions.ToCompositions (latent empty-sink bug) ---- + /// Pins the behaviour expressed by the test name: json compositions to compositions does not drop compositions on read path. [Test] public void JsonCompositions_ToCompositions_does_not_drop_compositions_on_read_path() { @@ -153,6 +157,7 @@ public void JsonCompositions_ToCompositions_does_not_drop_compositions_on_read_p // ---- JsonDataItem.ToDataItem (pre-existing CLEAN reference) ----- + /// Pins the behaviour expressed by the test name: json data item to data item preserves runtime type for typed subclass. [Test] public void JsonDataItem_ToDataItem_preserves_runtime_type_for_typed_subclass() { @@ -178,6 +183,7 @@ public void JsonDataItem_ToDataItem_preserves_runtime_type_for_typed_subclass() // ---- JsonEventValue.ToObservation ------------------------------- + /// Pins the behaviour expressed by the test name: json event value to observation preserves runtime type for typed subclass. [Test] public void JsonEventValue_ToObservation_preserves_runtime_type_for_typed_subclass() { @@ -206,6 +212,7 @@ public void JsonEventValue_ToObservation_preserves_runtime_type_for_typed_subcla Assert.That(observation.DataItemId, Is.EqualTo("msg-1")); } + /// Pins the behaviour expressed by the test name: json event value to observation preserves runtime type for asset changed. [Test] public void JsonEventValue_ToObservation_preserves_runtime_type_for_AssetChanged() { @@ -227,6 +234,7 @@ public void JsonEventValue_ToObservation_preserves_runtime_type_for_AssetChanged // ---- JsonCondition.ToCondition ---------------------------------- + /// Pins the behaviour expressed by the test name: json condition to condition preserves type string through envelope. [Test] public void JsonCondition_ToCondition_preserves_type_string_through_envelope() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderSchemaVersionXmlDocTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderSchemaVersionXmlDocTests.cs index 055fa9cf5..71e8a5613 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderSchemaVersionXmlDocTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderSchemaVersionXmlDocTests.cs @@ -10,9 +10,9 @@ namespace MTConnect.Tests.JsonCppagent /// /// Pins the XML-doc summary requirement on the SchemaVersion property in /// the three JSON-cppagent header DTO files. Each property must carry a - /// `` block immediately above the `[JsonPropertyName("schemaVersion")]` - /// attribute so consumers reading IntelliSense see the cppagent v2 - /// wire-shape semantics inline. + /// <summary> block immediately above the + /// [JsonPropertyName("schemaVersion")] attribute so consumers + /// reading IntelliSense see the cppagent v2 wire-shape semantics inline. /// /// Files covered: /// - libraries/MTConnect.NET-JSON-cppagent/Assets/JsonAssetsHeader.cs @@ -45,6 +45,8 @@ private static string FindRepoRoot() return string.Empty; } + /// Pins the behaviour expressed by the test name: header dto schema version has xmldoc summary. + /// The relative path. [TestCaseSource(nameof(HeaderFileRelativePaths))] public void Header_dto_schemaVersion_has_xmldoc_summary(string relativePath) { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderWireShapeE2ETests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderWireShapeE2ETests.cs index 97a74f70f..af1336bd4 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderWireShapeE2ETests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderWireShapeE2ETests.cs @@ -30,6 +30,9 @@ namespace MTConnect.Tests.JsonCppagent [Category("ComplianceMatrix")] public class JsonHeaderWireShapeE2ETests { + /// Pins the behaviour expressed by the test name: envelope carries schema version and test indicator. + /// The envelope kind. + /// The schema version. [TestCaseSource(typeof(JsonHeaderWireShapeMatrix), nameof(JsonHeaderWireShapeMatrix.Cases))] public void Envelope_carries_schemaVersion_and_testIndicator(string envelopeKind, string schemaVersion) { @@ -67,6 +70,7 @@ public void Envelope_carries_schemaVersion_and_testIndicator(string envelopeKind Assert.That(doc.RootElement.GetProperty("testIndicator").GetBoolean(), Is.False); } + /// Pins the behaviour expressed by the test name: streams envelope round trip preserves both fields. [Test] public void Streams_envelope_round_trip_preserves_both_fields() { @@ -82,6 +86,7 @@ public void Streams_envelope_round_trip_preserves_both_fields() Assert.That(roundTripped.TestIndicator, Is.True); } + /// Pins the behaviour expressed by the test name: devices envelope round trip preserves both fields. [Test] public void Devices_envelope_round_trip_preserves_both_fields() { @@ -97,6 +102,7 @@ public void Devices_envelope_round_trip_preserves_both_fields() Assert.That(roundTripped.TestIndicator, Is.True); } + /// Pins the behaviour expressed by the test name: assets envelope round trip preserves both fields. [Test] public void Assets_envelope_round_trip_preserves_both_fields() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderWireShapeMatrixTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderWireShapeMatrixTests.cs index 319e38221..8b8f6d9f1 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderWireShapeMatrixTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/JsonHeaderWireShapeMatrixTests.cs @@ -24,6 +24,7 @@ namespace MTConnect.Tests.JsonCppagent [Category("ComplianceMatrix")] public class JsonHeaderWireShapeMatrixTests { + /// Pins the behaviour expressed by the test name: matrix exposes three envelope kinds. [Test] public void Matrix_exposes_three_envelope_kinds() { @@ -36,6 +37,7 @@ public void Matrix_exposes_three_envelope_kinds() Assert.That(kinds, Is.EqualTo(new[] { "Assets", "Devices", "Streams" })); } + /// Pins the behaviour expressed by the test name: matrix covers v20 v23 v25 for each envelope. [Test] public void Matrix_covers_v20_v23_v25_for_each_envelope() { @@ -54,6 +56,7 @@ public void Matrix_covers_v20_v23_v25_for_each_envelope() } } + /// Pins the behaviour expressed by the test name: matrix class is internal static. [Test] public void Matrix_class_is_internal_static() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue128_HardcodedLiteralGuardTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue128_HardcodedLiteralGuardTests.cs index d8d461c96..e02b6b8a3 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue128_HardcodedLiteralGuardTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue128_HardcodedLiteralGuardTests.cs @@ -22,6 +22,8 @@ public class Issue128_HardcodedLiteralGuardTests private static readonly Regex HardcodedSchemaVersion = new(@"SchemaVersion\s*=\s*""[^""]+""\s*;", RegexOptions.Compiled); + /// Pins the behaviour expressed by the test name: source file must not hardcode schema version literal. + /// The relative path. [TestCase("Streams/JsonMTConnectStreams.cs")] [TestCase("Devices/JsonMTConnectDevices.cs")] public void Source_file_must_not_hardcode_schemaVersion_literal(string relativePath) diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue128_SchemaVersionConfiguredTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue128_SchemaVersionConfiguredTests.cs index 365ff4e84..170519e2c 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue128_SchemaVersionConfiguredTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue128_SchemaVersionConfiguredTests.cs @@ -19,6 +19,8 @@ namespace MTConnect.NET_JSON_cppagent_Tests.Regressions [TestFixture] public class Issue128_SchemaVersionConfiguredTests { + /// Pins the behaviour expressed by the test name: streams schema version equals configured. + /// The configured. [TestCaseSource(typeof(VersionMatrix), nameof(VersionMatrix.All))] public void Streams_schemaVersion_equals_configured(Version configured) { @@ -26,6 +28,8 @@ public void Streams_schemaVersion_equals_configured(Version configured) Assert.That(envelope.SchemaVersion, Is.EqualTo(configured.ToString())); } + /// Pins the behaviour expressed by the test name: devices schema version equals configured. + /// The configured. [TestCaseSource(typeof(VersionMatrix), nameof(VersionMatrix.All))] public void Devices_schemaVersion_equals_configured(Version configured) { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue129_NumericSampleNumberTokenTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue129_NumericSampleNumberTokenTests.cs index be73291e4..d13f339ba 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue129_NumericSampleNumberTokenTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/Issue129_NumericSampleNumberTokenTests.cs @@ -33,6 +33,9 @@ private static JsonElement Serialize(object value) return doc.RootElement.GetProperty("value").Clone(); } + /// Pins the behaviour expressed by the test name: float sample emits as json number. + /// The input. + /// The expected. [TestCase("1586.66", 1586.66)] [TestCase("-42.0", -42.0)] [TestCase("0", 0.0)] @@ -44,6 +47,7 @@ public void Float_sample_emits_as_json_number(string input, double expected) Assert.That(token.GetDouble(), Is.EqualTo(expected).Within(1e-9)); } + /// Pins the behaviour expressed by the test name: unavailable still emits as string. [Test] public void Unavailable_still_emits_as_string() { @@ -53,6 +57,8 @@ public void Unavailable_still_emits_as_string() Assert.That(token.GetString(), Is.EqualTo("UNAVAILABLE")); } + /// Pins the behaviour expressed by the test name: three space string value stays a string token. + /// The input. [TestCase("0 0 0")] [TestCase("1.5 -2.5 3.5")] public void ThreeSpace_string_value_stays_a_string_token(string input) @@ -66,6 +72,7 @@ public void ThreeSpace_string_value_stays_a_string_token(string input) Assert.That(token.GetString(), Is.EqualTo(input)); } + /// Pins the behaviour expressed by the test name: boxed double emits as json number. [Test] public void Boxed_double_emits_as_json_number() { @@ -75,6 +82,7 @@ public void Boxed_double_emits_as_json_number() Assert.That(token.GetDouble(), Is.EqualTo(3.14159).Within(1e-9)); } + /// Pins the behaviour expressed by the test name: invariant culture parsing is unaffected by thread culture. [Test] public void Invariant_culture_parsing_is_unaffected_by_thread_culture() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/SampleValueWriteStringValueGuardTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/SampleValueWriteStringValueGuardTests.cs index a12575740..d79295d5d 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/SampleValueWriteStringValueGuardTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/SampleValueWriteStringValueGuardTests.cs @@ -24,6 +24,7 @@ namespace MTConnect.NET_JSON_cppagent_Tests.Regressions [TestFixture] public class SampleValueWriteStringValueGuardTests { + /// Pins the behaviour expressed by the test name: json sample value does not write value directly as string. [Test] public void JsonSampleValue_does_not_write_value_directly_as_string() { @@ -49,6 +50,7 @@ public void JsonSampleValue_does_not_write_value_directly_as_string() "not inline string-token writes."); } + /// Pins the behaviour expressed by the test name: sample value carrier uses dedicated converter attribute. [Test] public void Sample_value_carrier_uses_dedicated_converter_attribute() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/SchemaVersionFieldsCoexistTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/SchemaVersionFieldsCoexistTests.cs index fee1d490c..fac5503da 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/SchemaVersionFieldsCoexistTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Regressions/SchemaVersionFieldsCoexistTests.cs @@ -45,6 +45,9 @@ namespace MTConnect.NET_JSON_cppagent_Tests.Regressions [Category("WireShape")] public class SchemaVersionFieldsCoexistTests { + /// Pins the behaviour expressed by the test name: schema version property exists with camel case json key. + /// The carrier. + /// The surface. [TestCase(typeof(JsonMTConnectStreams), "envelope")] [TestCase(typeof(JsonMTConnectDevices), "envelope")] [TestCase(typeof(JsonDevicesHeader), "Header")] @@ -67,6 +70,7 @@ public void SchemaVersion_property_exists_with_camelCase_json_key( $"`schemaVersion` (the cppagent wire-shape convention for scalar attributes)."); } + /// Pins the behaviour expressed by the test name: streams envelope and devices envelope carry independent schema version fields. [Test] public void Streams_envelope_and_devices_envelope_carry_independent_SchemaVersion_fields() { @@ -88,6 +92,7 @@ public void Streams_envelope_and_devices_envelope_carry_independent_SchemaVersio "not inherited from a shared base — the field is wired from document.Version."); } + /// Pins the behaviour expressed by the test name: devices envelope schema version distinct from header schema version. [Test] public void Devices_envelope_SchemaVersion_distinct_from_Header_SchemaVersion() { @@ -111,6 +116,9 @@ public void Devices_envelope_SchemaVersion_distinct_from_Header_SchemaVersion() // The XML doc presence guard. Reads the committed source files // (XML doc XML output is not deployed) so a future maintainer // cannot delete the doc comments without tripping a guard. + /// Pins the behaviour expressed by the test name: schema version property carries envelope vs header xml doc. + /// The relative source path. + /// The surface. [TestCase( "libraries/MTConnect.NET-JSON-cppagent/Streams/JsonMTConnectStreams.cs", "envelope")] diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/SanityTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/SanityTests.cs index 493270003..c601e6a3b 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/SanityTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/SanityTests.cs @@ -2,9 +2,11 @@ namespace MTConnect.NET_JSON_cppagent_Tests { + /// Pins the behaviour expressed by the test name: sanity tests. [TestFixture] public class SanityTests { + /// Pins the behaviour expressed by the test name: project loads and references m t connect n e t j s o n cppagent. [Test] public void Project_loads_and_references_MTConnect_NET_JSON_cppagent() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonConditionsArrayShapeTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonConditionsArrayShapeTests.cs index 5c982d9fd..f62e62c36 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonConditionsArrayShapeTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonConditionsArrayShapeTests.cs @@ -28,6 +28,7 @@ namespace MTConnect.NET_JSON_cppagent_Tests.Streams // - Prose: MTConnect Standard Part 2 section 13 "Condition". // - cppagent reference (v2.7.0.7): printer/json_printer.cpp // function print_condition. + /// Pins the behaviour expressed by the test name: json conditions array shape tests. [TestFixture] public class JsonConditionsArrayShapeTests { @@ -50,6 +51,7 @@ private static string FirstPropertyName(JsonElement element) } // Case 1 — empty conditions serialize as the array shape, not an object shape. + /// Pins the behaviour expressed by the test name: write empty conditions emits empty array. [Test] public void Write_EmptyConditions_EmitsEmptyArray() { @@ -61,6 +63,7 @@ public void Write_EmptyConditions_EmitsEmptyArray() } // Case 2 — one Normal entry produces a 1-element array with a Normal wrapper. + /// Pins the behaviour expressed by the test name: write single normal emits one normal wrapper. [Test] public void Write_SingleNormal_EmitsOneNormalWrapper() { @@ -83,6 +86,7 @@ public void Write_SingleNormal_EmitsOneNormalWrapper() } // Case 3 — Fault + Warning emit in Fault, Warning order per the converter. + /// Pins the behaviour expressed by the test name: write fault then warning emits in declared enumeration order. [Test] public void Write_FaultThenWarning_EmitsInDeclaredEnumerationOrder() { @@ -103,6 +107,7 @@ public void Write_FaultThenWarning_EmitsInDeclaredEnumerationOrder() } // Case 4 — all four levels populated emit in Fault, Warning, Normal, Unavailable order. + /// Pins the behaviour expressed by the test name: write all four levels emits in fault warning normal unavailable order. [Test] public void Write_AllFourLevels_EmitsInFaultWarningNormalUnavailableOrder() { @@ -133,6 +138,7 @@ public void Write_AllFourLevels_EmitsInFaultWarningNormalUnavailableOrder() } // Case 5 — multiple entries on one level produce one wrapper each in source order. + /// Pins the behaviour expressed by the test name: write multiple faults emits one wrapper per entry. [Test] public void Write_MultipleFaults_EmitsOneWrapperPerEntry() { @@ -167,6 +173,7 @@ public void Write_MultipleFaults_EmitsOneWrapperPerEntry() // Normal, Unavailable) on write. Pins the documented non-byte- // identical round-trip for interleaved input — see the type // comment on JsonConditionsConverter for the design rationale. + /// Pins the behaviour expressed by the test name: read array shape mixed level interleaving buckets by level. [Test] public void Read_ArrayShape_MixedLevelInterleaving_BucketsByLevel() { @@ -213,6 +220,7 @@ public void Read_ArrayShape_MixedLevelInterleaving_BucketsByLevel() } // Case 6 — array JSON round-trips through Deserialize/Serialize without drift. + /// Pins the behaviour expressed by the test name: round trip array shape is byte identical modulo whitespace. [Test] public void RoundTrip_ArrayShape_IsByteIdenticalModuloWhitespace() { @@ -232,6 +240,7 @@ public void RoundTrip_ArrayShape_IsByteIdenticalModuloWhitespace() } // Case 7 — legacy MTConnect JSON v1 object-keyed shape parses into the typed POCO. + /// Pins the behaviour expressed by the test name: read legacy object shape populates typed properties. [Test] public void Read_LegacyObjectShape_PopulatesTypedProperties() { @@ -255,6 +264,7 @@ public void Read_LegacyObjectShape_PopulatesTypedProperties() } // Case 8 — null write emits "null" and round-trips back to a null reference. + /// Pins the behaviour expressed by the test name: null write and read round trips to null. [Test] public void Null_WriteAndRead_RoundTripsToNull() { @@ -266,6 +276,7 @@ public void Null_WriteAndRead_RoundTripsToNull() } // Case 9 — invalid root token (number) raises JsonException with a recognisable message. + /// Pins the behaviour expressed by the test name: read invalid root token throws json exception. [Test] public void Read_InvalidRootToken_ThrowsJsonException() { @@ -277,6 +288,7 @@ public void Read_InvalidRootToken_ThrowsJsonException() // Coverage filler — the array-shape read path also handles all four levels // and rejects unknown level names + malformed wrapper objects. + /// Pins the behaviour expressed by the test name: read array shape populates all four levels. [Test] public void Read_ArrayShape_PopulatesAllFourLevels() { @@ -295,6 +307,7 @@ public void Read_ArrayShape_PopulatesAllFourLevels() Assert.That(parsed.Unavailable, Is.Not.Null); } + /// Pins the behaviour expressed by the test name: read array shape unknown level throws json exception. [Test] public void Read_ArrayShape_UnknownLevel_ThrowsJsonException() { @@ -306,6 +319,7 @@ public void Read_ArrayShape_UnknownLevel_ThrowsJsonException() Assert.That(ex!.Message, Does.Contain("Unknown Condition level")); } + /// Pins the behaviour expressed by the test name: read array shape non object element throws json exception. [Test] public void Read_ArrayShape_NonObjectElement_ThrowsJsonException() { @@ -317,6 +331,7 @@ public void Read_ArrayShape_NonObjectElement_ThrowsJsonException() Assert.That(ex!.Message, Does.Contain("expected object wrapper")); } + /// Pins the behaviour expressed by the test name: read array shape wrapper without property name throws json exception. [Test] public void Read_ArrayShape_WrapperWithoutPropertyName_ThrowsJsonException() { @@ -328,6 +343,7 @@ public void Read_ArrayShape_WrapperWithoutPropertyName_ThrowsJsonException() Assert.That(ex!.Message, Does.Contain("Expected property name")); } + /// Pins the behaviour expressed by the test name: read array shape wrapper with multiple properties throws json exception. [Test] public void Read_ArrayShape_WrapperWithMultipleProperties_ThrowsJsonException() { @@ -339,6 +355,7 @@ public void Read_ArrayShape_WrapperWithMultipleProperties_ThrowsJsonException() Assert.That(ex!.Message, Does.Contain("end of JsonConditions wrapper")); } + /// Pins the behaviour expressed by the test name: read array shape null entry throws json exception. [Test] public void Read_ArrayShape_NullEntry_ThrowsJsonException() { @@ -350,6 +367,7 @@ public void Read_ArrayShape_NullEntry_ThrowsJsonException() Assert.That(ex!.Message, Does.Contain("Null Condition entry")); } + /// Pins the behaviour expressed by the test name: read object shape unknown level throws json exception. [Test] public void Read_ObjectShape_UnknownLevel_ThrowsJsonException() { @@ -361,6 +379,7 @@ public void Read_ObjectShape_UnknownLevel_ThrowsJsonException() Assert.That(ex!.Message, Does.Contain("Unknown Condition level")); } + /// Pins the behaviour expressed by the test name: read object shape populates all four levels. [Test] public void Read_ObjectShape_PopulatesAllFourLevels() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonMTConnectStreamsSchemaVersionTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonMTConnectStreamsSchemaVersionTests.cs index 87e2b4577..0d6b126aa 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonMTConnectStreamsSchemaVersionTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonMTConnectStreamsSchemaVersionTests.cs @@ -20,6 +20,8 @@ namespace MTConnect.NET_JSON_cppagent_Tests.Streams [Category("SchemaVersionFromConfiguration")] public class JsonMTConnectStreamsSchemaVersionTests { + /// Pins the behaviour expressed by the test name: streams envelope schema version equals configured release. + /// The configured. [TestCaseSource(typeof(VersionMatrix), nameof(VersionMatrix.All))] public void Streams_envelope_schemaVersion_equals_configured_release(Version configured) { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueConverterEdgeCaseTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueConverterEdgeCaseTests.cs index 8a64d657c..cb16d108d 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueConverterEdgeCaseTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueConverterEdgeCaseTests.cs @@ -45,6 +45,8 @@ private static JsonElement SerializeValue(object value) // ---- non-finite numeric strings round-trip as JSON string tokens ---- + /// Pins the behaviour expressed by the test name: non finite numeric string emits as string token. + /// The non finite literal. [TestCase("NaN")] [TestCase("Infinity")] [TestCase("-Infinity")] @@ -60,6 +62,8 @@ public void Non_finite_numeric_string_emits_as_string_token(string nonFiniteLite // ---- empty / whitespace-only strings emit a JSON null token ---- + /// Pins the behaviour expressed by the test name: empty or whitespace string emits as null token. + /// The blank. [TestCase("")] [TestCase(" ")] [TestCase("\t")] @@ -86,6 +90,7 @@ public void Empty_or_whitespace_string_emits_as_null_token(string blank) // ---- non-string / non-numeric fallback uses InvariantCulture ---- + /// Pins the behaviour expressed by the test name: bool value fallback uses invariant culture. [Test] public void Bool_value_fallback_uses_invariant_culture() { @@ -101,6 +106,8 @@ public void Bool_value_fallback_uses_invariant_culture() // ---- ThreeSpace value path short-circuits before TryParse(double) ---- + /// Pins the behaviour expressed by the test name: three space string emits as string token. + /// The three space. [TestCase("1.5 -2.5 3.5")] [TestCase("0 0 0")] [TestCase("12345 0 0")] @@ -119,6 +126,8 @@ public void ThreeSpace_string_emits_as_string_token(string threeSpace) // ---- Read default branch throws JsonException on unsupported tokens ---- + /// Pins the behaviour expressed by the test name: read throws for unsupported token. + /// The payload. [TestCase("true")] [TestCase("false")] [TestCase("[1,2,3]")] diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueNumericTokenTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueNumericTokenTests.cs index c131bd28a..95ffb3416 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueNumericTokenTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueNumericTokenTests.cs @@ -36,6 +36,8 @@ private static JsonElement SerializeAndGetValue(object value) return doc.RootElement.GetProperty("value").Clone(); } + /// Pins the behaviour expressed by the test name: numeric string sample value emits number token. + /// The numeric literal. [TestCase("0")] [TestCase("42.5")] [TestCase("-17.0")] @@ -52,6 +54,8 @@ public void Numeric_string_sample_value_emits_number_token(string numericLiteral Assert.That(token.GetDouble(), Is.EqualTo(expected).Within(1e-9)); } + /// Pins the behaviour expressed by the test name: double sample value emits number token. + /// The numeric. [TestCase(42.5)] [TestCase(-17.0)] [TestCase(0.0)] @@ -63,6 +67,8 @@ public void Double_sample_value_emits_number_token(double numeric) Assert.That(token.GetDouble(), Is.EqualTo(numeric).Within(1e-9)); } + /// Pins the behaviour expressed by the test name: integer sample value emits number token. + /// The numeric. [TestCase(0)] [TestCase(-1)] [TestCase(2147483647)] @@ -74,6 +80,7 @@ public void Integer_sample_value_emits_number_token(int numeric) Assert.That(token.GetInt32(), Is.EqualTo(numeric)); } + /// Pins the behaviour expressed by the test name: three space string sample value emits string token. [Test] public void Three_space_string_sample_value_emits_string_token() { @@ -86,6 +93,7 @@ public void Three_space_string_sample_value_emits_string_token() Assert.That(token.GetString(), Is.EqualTo("1.5 -2.5 3.5")); } + /// Pins the behaviour expressed by the test name: unavailable sample value emits string token. [Test] public void Unavailable_sample_value_emits_string_token() { @@ -95,6 +103,7 @@ public void Unavailable_sample_value_emits_string_token() Assert.That(token.GetString(), Is.EqualTo("UNAVAILABLE")); } + /// Pins the behaviour expressed by the test name: null sample value is omitted. [Test] public void Null_sample_value_is_omitted() { @@ -105,6 +114,7 @@ public void Null_sample_value_is_omitted() "Null Value should be omitted by JsonIgnoreCondition.WhenWritingDefault"); } + /// Pins the behaviour expressed by the test name: bool sample value emits string token via invariant format. [Test] public void Bool_sample_value_emits_string_token_via_invariant_format() { @@ -117,6 +127,7 @@ public void Bool_sample_value_emits_string_token_via_invariant_format() Assert.That(token.GetString(), Is.EqualTo("True")); } + /// Pins the behaviour expressed by the test name: boxed null is written as null token when emitted. [Test] public void Boxed_null_is_written_as_null_token_when_emitted() { @@ -135,6 +146,7 @@ public void Boxed_null_is_written_as_null_token_when_emitted() Assert.That(json, Is.EqualTo("null")); } + /// Pins the behaviour expressed by the test name: read returns double for number token. [Test] public void Read_returns_double_for_number_token() { @@ -151,6 +163,7 @@ public void Read_returns_double_for_number_token() Assert.That((double)result!, Is.EqualTo(42.5).Within(1e-9)); } + /// Pins the behaviour expressed by the test name: read returns string for string token. [Test] public void Read_returns_string_for_string_token() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueToObservationTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueToObservationTests.cs index 86067492a..1729fa1da 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueToObservationTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonSampleValueToObservationTests.cs @@ -21,6 +21,7 @@ namespace MTConnect.NET_JSON_cppagent_Tests.Streams [TestFixture] public class JsonSampleValueToObservationTests { + /// Pins the behaviour expressed by the test name: to observation with null reset triggered does not store value. [Test] public void ToObservation_with_null_reset_triggered_does_not_store_value() { @@ -56,6 +57,7 @@ public void ToObservation_with_null_reset_triggered_does_not_store_value() "stray default-enum value."); } + /// Pins the behaviour expressed by the test name: to observation with supplied reset triggered sets enum. [Test] public void ToObservation_with_supplied_reset_triggered_sets_enum() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonStreamsHeaderSchemaVersionTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonStreamsHeaderSchemaVersionTests.cs index 8c356356c..b9b9899d1 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonStreamsHeaderSchemaVersionTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonStreamsHeaderSchemaVersionTests.cs @@ -27,6 +27,8 @@ namespace MTConnect.Tests.JsonCppagent.Streams [Category("ComplianceMatrix")] public class JsonStreamsHeaderSchemaVersionTests { + /// Pins the behaviour expressed by the test name: constructor with source header copies schema version. + /// The schema version. [TestCaseSource(typeof(JsonHeaderWireShapeMatrix), nameof(JsonHeaderWireShapeMatrix.SchemaVersionCases))] public void Constructor_with_source_header_copies_schemaVersion(string schemaVersion) { @@ -44,6 +46,8 @@ public void Constructor_with_source_header_copies_schemaVersion(string schemaVer "JsonStreamsHeader must copy SchemaVersion from the source IMTConnectStreamsHeader."); } + /// Pins the behaviour expressed by the test name: serialized streams header emits schema version property. + /// The schema version. [TestCaseSource(typeof(JsonHeaderWireShapeMatrix), nameof(JsonHeaderWireShapeMatrix.SchemaVersionCases))] public void Serialized_streams_header_emits_schemaVersion_property(string schemaVersion) { @@ -61,6 +65,7 @@ public void Serialized_streams_header_emits_schemaVersion_property(string schema Assert.That(v.GetString(), Is.EqualTo(schemaVersion)); } + /// Pins the behaviour expressed by the test name: serialized streams header emits test indicator property. [Test] public void Serialized_streams_header_emits_testIndicator_property() { @@ -80,6 +85,7 @@ public void Serialized_streams_header_emits_testIndicator_property() Assert.That(v.GetBoolean(), Is.False); } + /// Pins the behaviour expressed by the test name: reverse mapping round trips schema version. [Test] public void Reverse_mapping_round_trips_schemaVersion() { @@ -94,6 +100,7 @@ public void Reverse_mapping_round_trips_schemaVersion() "ToStreamsHeader must preserve SchemaVersion through the round trip."); } + /// Pins the behaviour expressed by the test name: constructor with null source does not throw. [Test] public void Constructor_with_null_source_does_not_throw() { @@ -103,6 +110,7 @@ public void Constructor_with_null_source_does_not_throw() Assert.That(jsonHeader.SchemaVersion, Is.Null); } + /// Pins the behaviour expressed by the test name: default constructor leaves schema version unset. [Test] public void Default_constructor_leaves_schemaVersion_unset() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonStreamsHeaderValidationTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonStreamsHeaderValidationTests.cs index 21b1fb88f..7f308891c 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonStreamsHeaderValidationTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/Streams/JsonStreamsHeaderValidationTests.cs @@ -25,6 +25,7 @@ namespace MTConnect.Tests.JsonCppagent.Streams [Category("CppAgentHeaderFieldsPresent")] public class JsonStreamsHeaderValidationTests { + /// Pins the behaviour expressed by the test name: constructor with source header copies validation. [Test] public void Constructor_with_source_header_copies_validation() { @@ -43,6 +44,7 @@ public void Constructor_with_source_header_copies_validation() "JsonStreamsHeader must copy Validation from the source IMTConnectStreamsHeader."); } + /// Pins the behaviour expressed by the test name: serialized streams header emits validation property. [Test] public void Serialized_streams_header_emits_validation_property() { @@ -60,6 +62,7 @@ public void Serialized_streams_header_emits_validation_property() Assert.That(v.GetBoolean(), Is.True); } + /// Pins the behaviour expressed by the test name: reverse mapping round trips validation. [Test] public void Reverse_mapping_round_trips_validation() { diff --git a/tests/MTConnect.NET-JSON-cppagent-Tests/TestHelpers/RepoRootLocatorTests.cs b/tests/MTConnect.NET-JSON-cppagent-Tests/TestHelpers/RepoRootLocatorTests.cs index 33171514e..0889b9bf3 100644 --- a/tests/MTConnect.NET-JSON-cppagent-Tests/TestHelpers/RepoRootLocatorTests.cs +++ b/tests/MTConnect.NET-JSON-cppagent-Tests/TestHelpers/RepoRootLocatorTests.cs @@ -14,6 +14,7 @@ namespace MTConnect.NET_JSON_cppagent_Tests.TestHelpers [TestFixture] public class RepoRootLocatorTests { + /// Pins the behaviour expressed by the test name: helper class is internal static. [Test] public void Helper_class_is_internal_static() { @@ -24,6 +25,7 @@ public void Helper_class_is_internal_static() "RepoRootLocator must be internal to the test project."); } + /// Pins the behaviour expressed by the test name: locate returns directory containing solution file. [Test] public void Locate_returns_directory_containing_solution_file() { From 0d873234fc4d263c25350e986e8a499052005c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:27:04 +0200 Subject: [PATCH 09/29] docs(common-tests): author XML doc comments on test surface --- .../Agents/AgentInstanceIdPersistenceTests.cs | 4 ++ .../Agents/AgentUuidConfigOverrideTests.cs | 2 + .../AgentUuidDeterministicDefaultTests.cs | 3 ++ .../AgentUuidLongitudinalInvariantsTests.cs | 3 ++ .../AssetCountAutoGeneratedDataSetTests.cs | 2 + .../AssetCountFactoryDataSetGuardTests.cs | 4 ++ .../NormalizeDeviceRequiredDataItemsTests.cs | 3 ++ .../Pallet/PalletMeasurementContractTests.cs | 18 ++++++++ .../Devices/AgentMetaDeviceNameTests.cs | 2 + .../Components/ComponentCtorDefaultsTests.cs | 2 + ...ControllersComponentMinimumVersionTests.cs | 1 + .../PolymorphicLeafCoverageTests.cs | 41 +++++++++++++++++++ ...CountDataItemDefaultRepresentationTests.cs | 6 +++ ...StructuredRepresentationClassifierTests.cs | 11 +++++ .../Devices/Device.cs | 3 ++ .../Devices/DeviceCtorDefaultsTests.cs | 12 ++++++ .../DeviceCtorStartupValidationTests.cs | 7 ++++ .../Devices/OrganizersAccessorsTests.cs | 24 +++++++++++ .../OrganizersControllerCarveOutTests.cs | 5 +++ .../Devices/OrganizersIsOrganizerTests.cs | 7 ++++ .../Devices/OrganizersSystemsEndToEndTests.cs | 4 ++ .../OrganizersSystemsRegressionTests.cs | 3 ++ .../Devices/OrganizersSystemsTests.cs | 14 +++++++ .../HeaderVersionFormattingCacheTests.cs | 4 ++ .../Headers/HeaderVersionRegressionTests.cs | 10 +++++ .../HeaderXmlDocExampleVersionTests.cs | 2 + .../InterfaceDataItemSubTypesTests.cs | 4 ++ .../ObservationFactoryRuntimeTypeTests.cs | 9 ++++ .../RegeneratedAssetsCoverageTests.cs | 14 +++++++ .../RegeneratedComponentsCoverageTests.cs | 8 ++++ .../RegeneratedConfigurationsCoverageTests.cs | 8 ++++ .../RegeneratedDataItemsCoverageTests.cs | 13 ++++++ .../RegeneratedTypesCoverageTests.cs | 24 +++++++++++ .../DeviceComponentDefaultsRegressionTests.cs | 7 ++++ .../V2_6_V2_7/MTConnectVersionsTests.cs | 6 +++ .../V2_6_V2_7/V2_6ComponentAndEnumTests.cs | 4 ++ .../V2_6_V2_7/V2_6DataItemTypeTests.cs | 7 ++++ .../V2_6_V2_7/V2_7ComponentTests.cs | 3 ++ .../V2_7ConfigurationDataSetTests.cs | 17 ++++++++ .../V2_6_V2_7/V2_7DataItemTypeTests.cs | 5 +++ .../V2_6_V2_7/V2_7SampleObservationTests.cs | 2 + 41 files changed, 328 insertions(+) diff --git a/tests/MTConnect.NET-Common-Tests/Agents/AgentInstanceIdPersistenceTests.cs b/tests/MTConnect.NET-Common-Tests/Agents/AgentInstanceIdPersistenceTests.cs index 9994fbfd1..37c860a1f 100644 --- a/tests/MTConnect.NET-Common-Tests/Agents/AgentInstanceIdPersistenceTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Agents/AgentInstanceIdPersistenceTests.cs @@ -129,6 +129,7 @@ private static MTConnectAgentInformation SimulateBootMonotonicAtTime( // Test 1: persisted file must contain a non-zero InstanceId // // ------------------------------------------------------------------ // + /// Pins the behaviour expressed by the test name: instance id reset must persist nonzero to state file. [Test] public void InstanceId_reset_must_persist_nonzero_to_state_file() { @@ -157,6 +158,7 @@ public void InstanceId_reset_must_persist_nonzero_to_state_file() // Test 2: XSD xs:minInclusive value='1' must be satisfied // // ------------------------------------------------------------------ // + /// Pins the behaviour expressed by the test name: instance id reset must be xsd spec compliant min inclusive 1. [Test] public void InstanceId_reset_must_be_xsd_spec_compliant_minInclusive_1() { @@ -187,6 +189,7 @@ public void InstanceId_reset_must_be_xsd_spec_compliant_minInclusive_1() // resets fall within the same tick; passes with Math.Max counter) // // ------------------------------------------------------------------ // + /// Pins the behaviour expressed by the test name: instance id two consecutive resets in same second must be strictly monotonic. [Test] public void InstanceId_two_consecutive_resets_in_same_second_must_be_strictly_monotonic() { @@ -258,6 +261,7 @@ public void InstanceId_two_consecutive_resets_in_same_second_must_be_strictly_mo // "collide_under_unix_second_resolution" documentation test) // // ------------------------------------------------------------------ // + /// Pins the behaviour expressed by the test name: instance id two consecutive resets in same second must be strictly monotonic under counter floor. [Test] public void InstanceId_two_consecutive_resets_in_same_second_must_be_strictly_monotonic_under_counter_floor() { diff --git a/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidConfigOverrideTests.cs b/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidConfigOverrideTests.cs index 51e61b266..f46444b56 100644 --- a/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidConfigOverrideTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidConfigOverrideTests.cs @@ -32,6 +32,7 @@ public class AgentUuidConfigOverrideTests private string? _stateFilePath; private string? _backupStateFile; + /// Sets up the fixture before each test. [SetUp] public void SetUp() { @@ -46,6 +47,7 @@ public void SetUp() } } + /// Tears down the fixture after each test. [TearDown] public void TearDown() { diff --git a/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidDeterministicDefaultTests.cs b/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidDeterministicDefaultTests.cs index 44da25058..a38c16877 100644 --- a/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidDeterministicDefaultTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidDeterministicDefaultTests.cs @@ -32,6 +32,7 @@ public class AgentUuidDeterministicDefaultTests private string? _stateFilePath; private string? _backupStateFile; + /// Sets up the fixture before each test. [OneTimeSetUp] public void OneTimeSetUp() { @@ -46,6 +47,7 @@ public void OneTimeSetUp() } } + /// Sets up the fixture before each test. [SetUp] public void SetUp() { @@ -58,6 +60,7 @@ public void SetUp() } } + /// Tears down the fixture after each test. [OneTimeTearDown] public void OneTimeTearDown() { diff --git a/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidLongitudinalInvariantsTests.cs b/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidLongitudinalInvariantsTests.cs index 7a89674c4..dfc745fdf 100644 --- a/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidLongitudinalInvariantsTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Agents/AgentUuidLongitudinalInvariantsTests.cs @@ -32,6 +32,7 @@ public class AgentUuidLongitudinalInvariantsTests private string? _stateFilePath; private string? _backupStateFile; + /// Sets up the fixture before each test. [OneTimeSetUp] public void OneTimeSetUp() { @@ -46,6 +47,7 @@ public void OneTimeSetUp() } } + /// Sets up the fixture before each test. [SetUp] public void SetUp() { @@ -58,6 +60,7 @@ public void SetUp() } } + /// Tears down the fixture after each test. [OneTimeTearDown] public void OneTimeTearDown() { diff --git a/tests/MTConnect.NET-Common-Tests/Agents/AssetCountAutoGeneratedDataSetTests.cs b/tests/MTConnect.NET-Common-Tests/Agents/AssetCountAutoGeneratedDataSetTests.cs index 25c11b8b9..5c66dc4c2 100644 --- a/tests/MTConnect.NET-Common-Tests/Agents/AssetCountAutoGeneratedDataSetTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Agents/AssetCountAutoGeneratedDataSetTests.cs @@ -27,6 +27,7 @@ namespace MTConnect.Tests.Common.Agents [Category("AssetCountIsDataSet")] public class AssetCountAutoGeneratedDataSetTests { + /// Pins the behaviour expressed by the test name: auto injected asset count has data set representation. [Test] public void AutoInjected_AssetCount_Has_DataSet_Representation() { @@ -53,6 +54,7 @@ public void AutoInjected_AssetCount_Has_DataSet_Representation() "auto-injected ASSET_COUNT must carry DATA_SET representation per MTConnect Part 2"); } + /// Pins the behaviour expressed by the test name: user declared asset count representation is preserved. [Test] public void UserDeclared_AssetCount_Representation_Is_Preserved() { diff --git a/tests/MTConnect.NET-Common-Tests/Agents/AssetCountFactoryDataSetGuardTests.cs b/tests/MTConnect.NET-Common-Tests/Agents/AssetCountFactoryDataSetGuardTests.cs index 557258f46..ec4e9fe32 100644 --- a/tests/MTConnect.NET-Common-Tests/Agents/AssetCountFactoryDataSetGuardTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Agents/AssetCountFactoryDataSetGuardTests.cs @@ -31,6 +31,8 @@ public class AssetCountFactoryDataSetGuardTests { private static readonly string[] _deviceIds = { "lathe-1", "mill-7", "robot-A" }; + /// Pins the behaviour expressed by the test name: add device auto injects asset count with data set representation. + /// The device id. [TestCaseSource(nameof(_deviceIds))] public void AddDevice_AutoInjects_AssetCount_With_DataSet_Representation(string deviceId) { @@ -56,6 +58,7 @@ public void AddDevice_AutoInjects_AssetCount_With_DataSet_Representation(string Is.EqualTo(DataItemRepresentation.DATA_SET)); } + /// Pins the behaviour expressed by the test name: add devices auto injects asset count with data set representation for every device. [Test] public void AddDevices_AutoInjects_AssetCount_With_DataSet_Representation_For_Every_Device() { @@ -86,6 +89,7 @@ public void AddDevices_AutoInjects_AssetCount_With_DataSet_Representation_For_Ev } } + /// Pins the behaviour expressed by the test name: add device with configuration auto injects asset count with data set representation. [Test] public void AddDevice_With_Configuration_AutoInjects_AssetCount_With_DataSet_Representation() { diff --git a/tests/MTConnect.NET-Common-Tests/Agents/NormalizeDeviceRequiredDataItemsTests.cs b/tests/MTConnect.NET-Common-Tests/Agents/NormalizeDeviceRequiredDataItemsTests.cs index 000796346..0ae0b07d2 100644 --- a/tests/MTConnect.NET-Common-Tests/Agents/NormalizeDeviceRequiredDataItemsTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Agents/NormalizeDeviceRequiredDataItemsTests.cs @@ -54,6 +54,8 @@ public class NormalizeDeviceRequiredDataItemsTests }; } + /// Pins the behaviour expressed by the test name: add device backfills all required data items exactly once. + /// The starting state. [TestCase("null")] [TestCase("empty")] [TestCase("with_availability")] @@ -83,6 +85,7 @@ public void AddDevice_backfills_all_required_dataItems_exactly_once(string start } } + /// Pins the behaviour expressed by the test name: add device preserves user provided data items alongside required ones. [Test] public void AddDevice_preserves_user_provided_dataItems_alongside_required_ones() { diff --git a/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs b/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs index 47d6d107b..e1ab3bbd2 100644 --- a/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs @@ -64,6 +64,9 @@ private static readonly (Type Type, string ExpectedTypeId)[] _palletMeasurements _palletMeasurements.Select(p => new TestCaseData(p.Type, p.ExpectedTypeId) .SetName($"{{m}}({p.Type.Name})")); + /// Pins the behaviour expressed by the test name: type id const equals sys m l class name. + /// The measurement type. + /// The expected type id. [Test] [TestCaseSource(nameof(PalletMeasurementCases))] public void TypeId_Const_Equals_SysML_ClassName(Type measurementType, string expectedTypeId) @@ -85,6 +88,9 @@ public void TypeId_Const_Equals_SysML_ClassName(Type measurementType, string exp $"{measurementType.Name}.TypeId must equal '{expectedTypeId}'"); } + /// Pins the behaviour expressed by the test name: code id const is empty. + /// The measurement type. + /// The expected type id. [Test] [TestCaseSource(nameof(PalletMeasurementCases))] public void CodeId_Const_Is_Empty(Type measurementType, string expectedTypeId) @@ -106,6 +112,9 @@ public void CodeId_Const_Is_Empty(Type measurementType, string expectedTypeId) $"{measurementType.Name}.CodeId must be empty for Pallet measurements"); } + /// Pins the behaviour expressed by the test name: default constructor stamps type. + /// The measurement type. + /// The expected type id. [Test] [TestCaseSource(nameof(PalletMeasurementCases))] public void Default_Constructor_Stamps_Type(Type measurementType, string expectedTypeId) @@ -120,6 +129,9 @@ public void Default_Constructor_Stamps_Type(Type measurementType, string expecte $"the default constructor must stamp Type = '{expectedTypeId}'"); } + /// Pins the behaviour expressed by the test name: double value constructor stamps type and value. + /// The measurement type. + /// The expected type id. [Test] [TestCaseSource(nameof(PalletMeasurementCases))] public void DoubleValue_Constructor_Stamps_Type_And_Value(Type measurementType, string expectedTypeId) @@ -137,6 +149,9 @@ public void DoubleValue_Constructor_Stamps_Type_And_Value(Type measurementType, $"the (double) constructor must stamp Value"); } + /// Pins the behaviour expressed by the test name: i measurement constructor copies fields and stamps type. + /// The measurement type. + /// The expected type id. [Test] [TestCaseSource(nameof(PalletMeasurementCases))] public void IMeasurement_Constructor_Copies_Fields_And_Stamps_Type(Type measurementType, string expectedTypeId) @@ -180,6 +195,9 @@ public void IMeasurement_Constructor_Copies_Fields_And_Stamps_Type(Type measurem "Units must be copied from source"); } + /// Pins the behaviour expressed by the test name: concrete subclass derives from base measurement. + /// The measurement type. + /// The expected type id. [Test] [TestCaseSource(nameof(PalletMeasurementCases))] public void Concrete_Subclass_Derives_From_Base_Measurement(Type measurementType, string expectedTypeId) diff --git a/tests/MTConnect.NET-Common-Tests/Devices/AgentMetaDeviceNameTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/AgentMetaDeviceNameTests.cs index 42fe46572..f09d43860 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/AgentMetaDeviceNameTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/AgentMetaDeviceNameTests.cs @@ -35,6 +35,7 @@ namespace MTConnect.Tests.Common.Devices [Category("AgentMetaDeviceNaming")] public class AgentMetaDeviceNameTests { + /// Pins the behaviour expressed by the test name: agent meta device default name matches cppagent pascal case convention. [Test] public void Agent_meta_device_default_Name_matches_cppagent_pascal_case_convention() { @@ -49,6 +50,7 @@ public void Agent_meta_device_default_Name_matches_cppagent_pascal_case_conventi + "diverging from cppagent's verbatim-attribute behaviour)."); } + /// Pins the behaviour expressed by the test name: agent meta device type remains agent type id. [Test] public void Agent_meta_device_Type_remains_Agent_TypeId() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/Components/ComponentCtorDefaultsTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/Components/ComponentCtorDefaultsTests.cs index c3ce2b261..44361e447 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/Components/ComponentCtorDefaultsTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/Components/ComponentCtorDefaultsTests.cs @@ -91,6 +91,7 @@ private static System.Collections.Generic.IEnumerable EnumerateConcreteCom return concreteSubclasses; } + /// Pins the behaviour expressed by the test name: object initializer still sets component name. [Test] public void Object_initializer_still_sets_Component_Name() { @@ -98,6 +99,7 @@ public void Object_initializer_still_sets_Component_Name() Assert.That(component.Name, Is.EqualTo("explicit")); } + /// Pins the behaviour expressed by the test name: direct setter still sets component name. [Test] public void Direct_setter_still_sets_Component_Name() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/Components/ControllersComponentMinimumVersionTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/Components/ControllersComponentMinimumVersionTests.cs index 40df77755..ed6bd945f 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/Components/ControllersComponentMinimumVersionTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/Components/ControllersComponentMinimumVersionTests.cs @@ -30,6 +30,7 @@ namespace MTConnect.Tests.Common.Devices.Components [Category("ControllersComponentMinimumVersion")] public class ControllersComponentMinimumVersionTests { + /// Pins the behaviour expressed by the test name: default constructor reports version20. [Test] public void Default_Constructor_Reports_Version20() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/Configurations/PolymorphicLeafCoverageTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/Configurations/PolymorphicLeafCoverageTests.cs index fdc37993d..3ac63fdc9 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/Configurations/PolymorphicLeafCoverageTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/Configurations/PolymorphicLeafCoverageTests.cs @@ -45,17 +45,25 @@ private static readonly (Type Abstract, Type Simple, Type DataSet, Type ISimple, (typeof(IAbstractTranslation), typeof(Translation), typeof(TranslationDataSet), typeof(ITranslation), typeof(ITranslationDataSet)), }; + /// Runs the abstract interfaces operation. + /// The result of the operation. public static IEnumerable AbstractInterfaces() => LeafShapes.Select(s => new TestCaseData(s.Abstract).SetName(s.Abstract.Name)); + /// Runs the simple leaves operation. + /// The result of the operation. public static IEnumerable SimpleLeaves() => LeafShapes.Select(s => new TestCaseData(s.Simple, s.Abstract, s.ISimple).SetName(s.Simple.Name)); + /// Runs the data set leaves operation. + /// The result of the operation. public static IEnumerable DataSetLeaves() => LeafShapes.Select(s => new TestCaseData(s.DataSet, s.Abstract, s.ISimple, s.IDataSet).SetName(s.DataSet.Name)); // ---------------- positive ---------------- + /// Pins the behaviour expressed by the test name: abstract interface has exactly two implementing classes. + /// The abstract interface. [TestCaseSource(nameof(AbstractInterfaces))] public void Abstract_interface_has_exactly_two_implementing_classes(Type abstractInterface) { @@ -69,6 +77,10 @@ public void Abstract_interface_has_exactly_two_implementing_classes(Type abstrac + $"found {implementors.Count}: {string.Join(", ", implementors.Select(t => t.Name))}"); } + /// Pins the behaviour expressed by the test name: simple leaf implements simple interface and inherits abstract interface. + /// The simple type. + /// The abstract interface. + /// The simple interface. [TestCaseSource(nameof(SimpleLeaves))] public void Simple_leaf_implements_simple_interface_and_inherits_abstract_interface( Type simpleType, Type abstractInterface, Type simpleInterface) @@ -81,6 +93,10 @@ public void Simple_leaf_implements_simple_interface_and_inherits_abstract_interf $"{simpleType.Name} must inherit {abstractInterface.Name}"); } + /// Pins the behaviour expressed by the test name: simple leaf does not implement i data set. + /// The simple type. + /// The abstract interface. + /// The simple interface. [TestCaseSource(nameof(SimpleLeaves))] public void Simple_leaf_does_not_implement_IDataSet( Type simpleType, Type abstractInterface, Type simpleInterface) @@ -89,6 +105,10 @@ public void Simple_leaf_does_not_implement_IDataSet( $"{simpleType.Name} (simple variant) must NOT implement IDataSet"); } + /// Pins the behaviour expressed by the test name: simple leaf constructs via parameterless ctor. + /// The simple type. + /// The abstract interface. + /// The simple interface. [TestCaseSource(nameof(SimpleLeaves))] public void Simple_leaf_constructs_via_parameterless_ctor( Type simpleType, Type abstractInterface, Type simpleInterface) @@ -99,6 +119,11 @@ public void Simple_leaf_constructs_via_parameterless_ctor( Assert.That(instance, Is.Not.Null); } + /// Pins the behaviour expressed by the test name: data set leaf implements dataset simple and abstract interfaces. + /// The data set type. + /// The abstract interface. + /// The simple interface. + /// The data set interface. [TestCaseSource(nameof(DataSetLeaves))] public void DataSet_leaf_implements_dataset_simple_and_abstract_interfaces( Type dataSetType, Type abstractInterface, Type simpleInterface, Type dataSetInterface) @@ -111,6 +136,11 @@ public void DataSet_leaf_implements_dataset_simple_and_abstract_interfaces( $"{dataSetType.Name} must implement IDataSet"); } + /// Pins the behaviour expressed by the test name: data set leaf constructs via parameterless ctor. + /// The data set type. + /// The abstract interface. + /// The simple interface. + /// The data set interface. [TestCaseSource(nameof(DataSetLeaves))] public void DataSet_leaf_constructs_via_parameterless_ctor( Type dataSetType, Type abstractInterface, Type simpleInterface, Type dataSetInterface) @@ -123,6 +153,8 @@ public void DataSet_leaf_constructs_via_parameterless_ctor( // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: abstract interface carries no member definitions. + /// The abstract interface. [TestCaseSource(nameof(AbstractInterfaces))] public void Abstract_interface_carries_no_member_definitions(Type abstractInterface) { @@ -139,6 +171,10 @@ public void Abstract_interface_carries_no_member_definitions(Type abstractInterf + string.Join(", ", members.Select(m => m.Name))); } + /// Pins the behaviour expressed by the test name: simple leaf inherits abstract base. + /// The simple type. + /// The abstract interface. + /// The simple interface. [TestCaseSource(nameof(SimpleLeaves))] public void Simple_leaf_inherits_AbstractBase( Type simpleType, Type abstractInterface, Type simpleInterface) @@ -152,6 +188,11 @@ public void Simple_leaf_inherits_AbstractBase( Assert.That(simpleType.BaseType.Name, Does.StartWith("Abstract")); } + /// Pins the behaviour expressed by the test name: data set leaf inherits abstract base. + /// The data set type. + /// The abstract interface. + /// The simple interface. + /// The data set interface. [TestCaseSource(nameof(DataSetLeaves))] public void DataSet_leaf_inherits_AbstractBase( Type dataSetType, Type abstractInterface, Type simpleInterface, Type dataSetInterface) diff --git a/tests/MTConnect.NET-Common-Tests/Devices/DataItems/AssetCountDataItemDefaultRepresentationTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/DataItems/AssetCountDataItemDefaultRepresentationTests.cs index b685adfe7..469370fea 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/DataItems/AssetCountDataItemDefaultRepresentationTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/DataItems/AssetCountDataItemDefaultRepresentationTests.cs @@ -39,6 +39,7 @@ namespace MTConnect.Tests.Common.Devices.DataItems [Category("AssetCountIsDataSet")] public class AssetCountDataItemDefaultRepresentationTests { + /// Pins the behaviour expressed by the test name: default representation const equals data set. [Test] public void DefaultRepresentation_Const_Equals_DataSet() { @@ -48,6 +49,7 @@ public void DefaultRepresentation_Const_Equals_DataSet() "AssetCountDataItem.DefaultRepresentation must equal DATA_SET"); } + /// Pins the behaviour expressed by the test name: parameterless constructor stamps data set representation. [Test] public void Parameterless_Constructor_Stamps_DataSet_Representation() { @@ -59,6 +61,7 @@ public void Parameterless_Constructor_Stamps_DataSet_Representation() "the parameterless constructor must stamp Representation = DATA_SET"); } + /// Pins the behaviour expressed by the test name: device id constructor stamps data set representation. [Test] public void DeviceId_Constructor_Stamps_DataSet_Representation() { @@ -70,6 +73,7 @@ public void DeviceId_Constructor_Stamps_DataSet_Representation() "the (deviceId) constructor must stamp Representation = DATA_SET"); } + /// Pins the behaviour expressed by the test name: device id constructor builds v2 conformant id. [Test] public void DeviceId_Constructor_Builds_V2_Conformant_Id() { @@ -84,6 +88,7 @@ public void DeviceId_Constructor_Builds_V2_Conformant_Id() Assert.That(item.Id, Is.EqualTo($"Device-1_{AssetCountDataItem.NameId}")); } + /// Pins the behaviour expressed by the test name: minimum version reports version20. [Test] public void MinimumVersion_Reports_Version20() { @@ -98,6 +103,7 @@ public void MinimumVersion_Reports_Version20() Assert.That(item.MinimumVersion, Is.EqualTo(MTConnectVersions.Version20)); } + /// Pins the behaviour expressed by the test name: default representation field is public const data set. [Test] public void DefaultRepresentation_Field_Is_Public_Const_DataSet() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/DataItems/StructuredRepresentationClassifierTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/DataItems/StructuredRepresentationClassifierTests.cs index c7609ec08..2f824b523 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/DataItems/StructuredRepresentationClassifierTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/DataItems/StructuredRepresentationClassifierTests.cs @@ -43,6 +43,7 @@ namespace MTConnect.Tests.Common.Devices.DataItems [Category("StructuredRepresentationClassifier")] public class StructuredRepresentationClassifierTests { + /// Pins the behaviour expressed by the test name: alarm limits default representation is data set. [Test] public void AlarmLimits_DefaultRepresentation_Is_DataSet() { @@ -51,6 +52,7 @@ public void AlarmLimits_DefaultRepresentation_Is_DataSet() Is.EqualTo(DataItemRepresentation.DATA_SET)); } + /// Pins the behaviour expressed by the test name: alarm limit default representation is data set. [Test] public void AlarmLimit_DefaultRepresentation_Is_DataSet() { @@ -59,6 +61,7 @@ public void AlarmLimit_DefaultRepresentation_Is_DataSet() Is.EqualTo(DataItemRepresentation.DATA_SET)); } + /// Pins the behaviour expressed by the test name: control limits default representation is data set. [Test] public void ControlLimits_DefaultRepresentation_Is_DataSet() { @@ -67,6 +70,7 @@ public void ControlLimits_DefaultRepresentation_Is_DataSet() Is.EqualTo(DataItemRepresentation.DATA_SET)); } + /// Pins the behaviour expressed by the test name: control limit default representation is data set. [Test] public void ControlLimit_DefaultRepresentation_Is_DataSet() { @@ -75,6 +79,7 @@ public void ControlLimit_DefaultRepresentation_Is_DataSet() Is.EqualTo(DataItemRepresentation.DATA_SET)); } + /// Pins the behaviour expressed by the test name: location address default representation is data set. [Test] public void LocationAddress_DefaultRepresentation_Is_DataSet() { @@ -83,6 +88,7 @@ public void LocationAddress_DefaultRepresentation_Is_DataSet() Is.EqualTo(DataItemRepresentation.DATA_SET)); } + /// Pins the behaviour expressed by the test name: location spatial geographic default representation is data set. [Test] public void LocationSpatialGeographic_DefaultRepresentation_Is_DataSet() { @@ -91,6 +97,7 @@ public void LocationSpatialGeographic_DefaultRepresentation_Is_DataSet() Is.EqualTo(DataItemRepresentation.DATA_SET)); } + /// Pins the behaviour expressed by the test name: specification limits default representation is data set. [Test] public void SpecificationLimits_DefaultRepresentation_Is_DataSet() { @@ -99,6 +106,7 @@ public void SpecificationLimits_DefaultRepresentation_Is_DataSet() Is.EqualTo(DataItemRepresentation.DATA_SET)); } + /// Pins the behaviour expressed by the test name: specification limit default representation is data set. [Test] public void SpecificationLimit_DefaultRepresentation_Is_DataSet() { @@ -107,6 +115,7 @@ public void SpecificationLimit_DefaultRepresentation_Is_DataSet() Is.EqualTo(DataItemRepresentation.DATA_SET)); } + /// Pins the behaviour expressed by the test name: sensor attachment default representation is data set. [Test] public void SensorAttachment_DefaultRepresentation_Is_DataSet() { @@ -115,6 +124,7 @@ public void SensorAttachment_DefaultRepresentation_Is_DataSet() Is.EqualTo(DataItemRepresentation.DATA_SET)); } + /// Pins the behaviour expressed by the test name: feature measurement default representation stays table. [Test] public void FeatureMeasurement_DefaultRepresentation_Stays_Table() { @@ -126,6 +136,7 @@ public void FeatureMeasurement_DefaultRepresentation_Stays_Table() Is.EqualTo(DataItemRepresentation.TABLE)); } + /// Pins the behaviour expressed by the test name: maintenance list default representation stays table. [Test] public void MaintenanceList_DefaultRepresentation_Stays_Table() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/Device.cs b/tests/MTConnect.NET-Common-Tests/Devices/Device.cs index 7cc7a7d62..452e8e4e0 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/Device.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/Device.cs @@ -3,14 +3,17 @@ namespace MTConnect.Tests.Common.Devices { + /// Represents the device. public class Device { + /// Sets up the fixture before each test. [SetUp] public void Setup() { } + /// Pins the behaviour expressed by the test name: test1. [Test] public void Test1() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorDefaultsTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorDefaultsTests.cs index 9e53b2d4c..d96d6a15e 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorDefaultsTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorDefaultsTests.cs @@ -18,6 +18,7 @@ namespace MTConnect.Tests.Common.DeviceCtorDefaults [Category("DeviceComponentDefaultsRemoved")] public class DeviceCtorDefaultsTests { + /// Pins the behaviour expressed by the test name: default constructor leaves id null. [Test] public void Default_constructor_leaves_Id_null() { @@ -25,6 +26,7 @@ public void Default_constructor_leaves_Id_null() Assert.That(device.Id, Is.Null); } + /// Pins the behaviour expressed by the test name: default constructor leaves name null. [Test] public void Default_constructor_leaves_Name_null() { @@ -32,6 +34,7 @@ public void Default_constructor_leaves_Name_null() Assert.That(device.Name, Is.Null); } + /// Pins the behaviour expressed by the test name: default constructor leaves uuid null. [Test] public void Default_constructor_leaves_Uuid_null() { @@ -39,6 +42,7 @@ public void Default_constructor_leaves_Uuid_null() Assert.That(device.Uuid, Is.Null); } + /// Pins the behaviour expressed by the test name: object initializer still sets id. [Test] public void Object_initializer_still_sets_Id() { @@ -46,6 +50,7 @@ public void Object_initializer_still_sets_Id() Assert.That(device.Id, Is.EqualTo("device-1")); } + /// Pins the behaviour expressed by the test name: object initializer still sets name. [Test] public void Object_initializer_still_sets_Name() { @@ -53,6 +58,7 @@ public void Object_initializer_still_sets_Name() Assert.That(device.Name, Is.EqualTo("spindle-A")); } + /// Pins the behaviour expressed by the test name: object initializer still sets uuid. [Test] public void Object_initializer_still_sets_Uuid() { @@ -60,6 +66,7 @@ public void Object_initializer_still_sets_Uuid() Assert.That(device.Uuid, Is.EqualTo("F1")); } + /// Pins the behaviour expressed by the test name: sequential default constructors produce identical null identity. [Test] public void Sequential_default_constructors_produce_identical_null_identity() { @@ -74,6 +81,7 @@ public void Sequential_default_constructors_produce_identical_null_identity() Assert.That(second.Uuid, Is.Null); } + /// Pins the behaviour expressed by the test name: default constructor still sets type. [Test] public void Default_constructor_still_sets_Type() { @@ -82,6 +90,7 @@ public void Default_constructor_still_sets_Type() Assert.That(device.Type, Is.EqualTo(Device.TypeId)); } + /// Pins the behaviour expressed by the test name: default constructor still initializes collections. [Test] public void Default_constructor_still_initializes_collections() { @@ -92,6 +101,7 @@ public void Default_constructor_still_initializes_collections() Assert.That(device.Compositions, Is.Not.Null); } + /// Pins the behaviour expressed by the test name: agent default constructor leaves uuid null. [Test] public void Agent_default_constructor_leaves_Uuid_null() { @@ -99,6 +109,7 @@ public void Agent_default_constructor_leaves_Uuid_null() Assert.That(agent.Uuid, Is.Null); } + /// Pins the behaviour expressed by the test name: agent default constructor leaves id null. [Test] public void Agent_default_constructor_leaves_Id_null() { @@ -106,6 +117,7 @@ public void Agent_default_constructor_leaves_Id_null() Assert.That(agent.Id, Is.Null); } + /// Pins the behaviour expressed by the test name: agent default constructor leaves name null. [Test] public void Agent_default_constructor_leaves_Name_null() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorStartupValidationTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorStartupValidationTests.cs index 397264c57..c18e2b64d 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorStartupValidationTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/DeviceCtorStartupValidationTests.cs @@ -36,6 +36,7 @@ namespace MTConnect.Tests.Common.DeviceCtorDefaults [Category("DeviceComponentDefaultsRemoved")] public class DeviceCtorStartupValidationTests { + /// Pins the behaviour expressed by the test name: add device with null uuid raises invalid device added with clear message. [Test] public void AddDevice_with_null_uuid_raises_invalid_device_added_with_clear_message() { @@ -77,6 +78,7 @@ public void AddDevice_with_null_uuid_raises_invalid_device_added_with_clear_mess "ValidationResult.Message must name the offending Device's type so the operator can locate it in their config."); } + /// Pins the behaviour expressed by the test name: add device with empty uuid raises invalid device added with clear message. [Test] public void AddDevice_with_empty_uuid_raises_invalid_device_added_with_clear_message() { @@ -104,6 +106,7 @@ public void AddDevice_with_empty_uuid_raises_invalid_device_added_with_clear_mes Assert.That(capturedResult.Message, Does.Contain("Uuid")); } + /// Pins the behaviour expressed by the test name: add device with non null uuid does not raise invalid device added. [Test] public void AddDevice_with_non_null_uuid_does_not_raise_invalid_device_added() { @@ -130,6 +133,7 @@ public void AddDevice_with_non_null_uuid_does_not_raise_invalid_device_added() "InvalidDeviceAdded must NOT fire when the Device's Uuid is well-formed."); } + /// Pins the behaviour expressed by the test name: add device event message names registration index. [Test] public void AddDevice_event_message_names_registration_index() { @@ -153,6 +157,7 @@ public void AddDevice_event_message_names_registration_index() "ValidationResult.Message must include the offending Device's registration index (1) so the operator can locate it."); } + /// Pins the behaviour expressed by the test name: validate device returns invalid for null uuid without mutating buffer. [Test] public void ValidateDevice_returns_invalid_for_null_uuid_without_mutating_buffer() { @@ -172,6 +177,7 @@ public void ValidateDevice_returns_invalid_for_null_uuid_without_mutating_buffer "ValidateDevice must not register the Device, regardless of the validation outcome."); } + /// Pins the behaviour expressed by the test name: validate device returns valid for well formed device. [Test] public void ValidateDevice_returns_valid_for_well_formed_device() { @@ -184,6 +190,7 @@ public void ValidateDevice_returns_valid_for_well_formed_device() Assert.That(result.Message, Is.Null.Or.Empty); } + /// Pins the behaviour expressed by the test name: validate device returns invalid for null device. [Test] public void ValidateDevice_returns_invalid_for_null_device() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersAccessorsTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersAccessorsTests.cs index 0e773cd8e..aea6c3495 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersAccessorsTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersAccessorsTests.cs @@ -16,10 +16,12 @@ namespace MTConnect.Tests.Common.SystemsOrganizer { + /// Pins the behaviour expressed by the test name: organizers accessors tests. [TestFixture] [Category("OrganizersAccessors")] public class OrganizersAccessorsTests { + /// Pins the behaviour expressed by the test name: components lists every first class organizer. [Test] public void Components_lists_every_first_class_organizer() { @@ -40,12 +42,14 @@ public void Components_lists_every_first_class_organizer() Assert.That(Organizers.Components, Is.EquivalentTo(expected)); } + /// Pins the behaviour expressed by the test name: adapters lists adapter component. [Test] public void Adapters_lists_AdapterComponent() { Assert.That(Organizers.Adapters, Is.EquivalentTo(new[] { AdapterComponent.TypeId })); } + /// Pins the behaviour expressed by the test name: auxiliaries lists known auxiliary components. [Test] public void Auxiliaries_lists_known_auxiliary_components() { @@ -59,6 +63,7 @@ public void Auxiliaries_lists_known_auxiliary_components() })); } + /// Pins the behaviour expressed by the test name: axes lists linear and rotary. [Test] public void Axes_lists_Linear_and_Rotary() { @@ -69,12 +74,14 @@ public void Axes_lists_Linear_and_Rotary() })); } + /// Pins the behaviour expressed by the test name: controllers lists controller component. [Test] public void Controllers_lists_ControllerComponent() { Assert.That(Organizers.Controllers, Is.EquivalentTo(new[] { ControllerComponent.TypeId })); } + /// Pins the behaviour expressed by the test name: interfaces lists known interface components. [Test] public void Interfaces_lists_known_interface_components() { @@ -87,24 +94,28 @@ public void Interfaces_lists_known_interface_components() })); } + /// Pins the behaviour expressed by the test name: materials lists stock component. [Test] public void Materials_lists_StockComponent() { Assert.That(Organizers.Materials, Is.EquivalentTo(new[] { StockComponent.TypeId })); } + /// Pins the behaviour expressed by the test name: parts lists part occurrence component. [Test] public void Parts_lists_PartOccurrenceComponent() { Assert.That(Organizers.Parts, Is.EquivalentTo(new[] { PartOccurrenceComponent.TypeId })); } + /// Pins the behaviour expressed by the test name: processes lists process occurrence component. [Test] public void Processes_lists_ProcessOccurrenceComponent() { Assert.That(Organizers.Processes, Is.EquivalentTo(new[] { ProcessOccurrenceComponent.TypeId })); } + /// Pins the behaviour expressed by the test name: resources lists known resource components. [Test] public void Resources_lists_known_resource_components() { @@ -115,6 +126,7 @@ public void Resources_lists_known_resource_components() })); } + /// Pins the behaviour expressed by the test name: structures lists link component. [Test] public void Structures_lists_LinkComponent() { @@ -124,18 +136,22 @@ public void Structures_lists_LinkComponent() // GetOrganizerType — exhaustive branch coverage of the else-if chain. // Each test names one organizer family and supplies a representative // member from that family, so every branch in the chain executes. + /// Pins the behaviour expressed by the test name: get organizer type null input returns null. + /// The type id. [TestCase(null)] public void GetOrganizerType_null_input_returns_null(string? typeId) { Assert.That(Organizers.GetOrganizerType(typeId), Is.Null); } + /// Pins the behaviour expressed by the test name: get organizer type unknown type returns null. [Test] public void GetOrganizerType_unknown_type_returns_null() { Assert.That(Organizers.GetOrganizerType("ThisIsNotAnyKnownComponentType"), Is.Null); } + /// Pins the behaviour expressed by the test name: get organizer type for adapter returns adapters. [Test] public void GetOrganizerType_for_adapter_returns_Adapters() { @@ -143,6 +159,7 @@ public void GetOrganizerType_for_adapter_returns_Adapters() Is.EqualTo(AdaptersComponent.TypeId)); } + /// Pins the behaviour expressed by the test name: get organizer type for auxiliary returns auxiliaries. [Test] public void GetOrganizerType_for_auxiliary_returns_Auxiliaries() { @@ -150,6 +167,7 @@ public void GetOrganizerType_for_auxiliary_returns_Auxiliaries() Is.EqualTo(AuxiliariesComponent.TypeId)); } + /// Pins the behaviour expressed by the test name: get organizer type for axis returns axes. [Test] public void GetOrganizerType_for_axis_returns_Axes() { @@ -157,6 +175,7 @@ public void GetOrganizerType_for_axis_returns_Axes() Is.EqualTo(AxesComponent.TypeId)); } + /// Pins the behaviour expressed by the test name: get organizer type for interface returns interfaces. [Test] public void GetOrganizerType_for_interface_returns_Interfaces() { @@ -164,6 +183,7 @@ public void GetOrganizerType_for_interface_returns_Interfaces() Is.EqualTo(InterfacesComponent.TypeId)); } + /// Pins the behaviour expressed by the test name: get organizer type for material returns materials. [Test] public void GetOrganizerType_for_material_returns_Materials() { @@ -171,6 +191,7 @@ public void GetOrganizerType_for_material_returns_Materials() Is.EqualTo(MaterialsComponent.TypeId)); } + /// Pins the behaviour expressed by the test name: get organizer type for part returns parts. [Test] public void GetOrganizerType_for_part_returns_Parts() { @@ -178,6 +199,7 @@ public void GetOrganizerType_for_part_returns_Parts() Is.EqualTo(PartsComponent.TypeId)); } + /// Pins the behaviour expressed by the test name: get organizer type for process returns processes. [Test] public void GetOrganizerType_for_process_returns_Processes() { @@ -185,6 +207,7 @@ public void GetOrganizerType_for_process_returns_Processes() Is.EqualTo(ProcessesComponent.TypeId)); } + /// Pins the behaviour expressed by the test name: get organizer type for resource returns resources. [Test] public void GetOrganizerType_for_resource_returns_Resources() { @@ -192,6 +215,7 @@ public void GetOrganizerType_for_resource_returns_Resources() Is.EqualTo(ResourcesComponent.TypeId)); } + /// Pins the behaviour expressed by the test name: get organizer type for structure returns structures. [Test] public void GetOrganizerType_for_structure_returns_Structures() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersControllerCarveOutTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersControllerCarveOutTests.cs index 5701e9e39..be70fe2af 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersControllerCarveOutTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersControllerCarveOutTests.cs @@ -19,10 +19,12 @@ namespace MTConnect.Tests.Common.SystemsOrganizer { + /// Pins the behaviour expressed by the test name: organizers controller carve out tests. [TestFixture] [Category("OrganizersControllerCarveOut")] public class OrganizersControllerCarveOutTests { + /// Pins the behaviour expressed by the test name: organizers systems does not list controller component. [Test] public void Organizers_Systems_does_not_list_ControllerComponent() { @@ -35,6 +37,7 @@ public void Organizers_Systems_does_not_list_ControllerComponent() $"both makes `Organizers.GetOrganizerType()` order-dependent."); } + /// Pins the behaviour expressed by the test name: organizers controllers lists controller component. [Test] public void Organizers_Controllers_lists_ControllerComponent() { @@ -46,6 +49,7 @@ public void Organizers_Controllers_lists_ControllerComponent() $"`{ControllersComponent.TypeId}`."); } + /// Pins the behaviour expressed by the test name: get organizer type for controller resolves to controllers independent of ordering. [Test] public void GetOrganizerType_for_Controller_resolves_to_Controllers_independent_of_ordering() { @@ -62,6 +66,7 @@ public void GetOrganizerType_for_Controller_resolves_to_Controllers_independent_ $"the underlying organizer lookup is implemented."); } + /// Pins the behaviour expressed by the test name: controller appears in exactly one organizer list. [Test] public void Controller_appears_in_exactly_one_organizer_list() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersIsOrganizerTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersIsOrganizerTests.cs index c2cfece6c..92c6c1b7e 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersIsOrganizerTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersIsOrganizerTests.cs @@ -22,10 +22,13 @@ namespace MTConnect.Tests.Common.SystemsOrganizer { + /// Pins the behaviour expressed by the test name: organizers is organizer tests. [TestFixture] [Category("OrganizersIsOrganizer")] public class OrganizersIsOrganizerTests { + /// Pins the behaviour expressed by the test name: is organizer returns true for each first class organizer. + /// The organizer name. [TestCase(nameof(AdaptersComponent))] [TestCase(nameof(AuxiliariesComponent))] [TestCase(nameof(AxesComponent))] @@ -47,6 +50,7 @@ public void IsOrganizer_returns_true_for_each_first_class_organizer(string organ $"`Organizers.IsOrganizer(\"{typeId}\")` must return true."); } + /// Pins the behaviour expressed by the test name: is organizer returns false for member components. [Test] public void IsOrganizer_returns_false_for_member_components() { @@ -57,18 +61,21 @@ public void IsOrganizer_returns_false_for_member_components() Assert.That(Organizers.IsOrganizer(LinearComponent.TypeId), Is.False); } + /// Pins the behaviour expressed by the test name: is organizer returns false for unknown type. [Test] public void IsOrganizer_returns_false_for_unknown_type() { Assert.That(Organizers.IsOrganizer("ThisIsNotAnyKnownComponentType"), Is.False); } + /// Pins the behaviour expressed by the test name: is organizer returns false for null. [Test] public void IsOrganizer_returns_false_for_null() { Assert.That(Organizers.IsOrganizer(null), Is.False); } + /// Pins the behaviour expressed by the test name: is organizer returns false for empty string. [Test] public void IsOrganizer_returns_false_for_empty_string() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsEndToEndTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsEndToEndTests.cs index ce55fe712..9f0a37b77 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsEndToEndTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsEndToEndTests.cs @@ -26,6 +26,7 @@ namespace MTConnect.Tests.Common.SystemsOrganizer { + /// Pins the behaviour expressed by the test name: organizers systems end to end tests. [TestFixture] [Category("OrganizersSystemsEndToEnd")] public class OrganizersSystemsEndToEndTests @@ -55,6 +56,7 @@ public class OrganizersSystemsEndToEndTests typeof(WorkEnvelopeComponent), }; + /// Pins the behaviour expressed by the test name: all auto wrapped system peers land under single systems organizer. [Test] public void All_auto_wrapped_system_peers_land_under_single_Systems_organizer() { @@ -87,6 +89,7 @@ public void All_auto_wrapped_system_peers_land_under_single_Systems_organizer() "The `` organizer must enumerate every System peer as a direct child."); } + /// Pins the behaviour expressed by the test name: heating and protective share systems organizer after separate add component calls. [Test] public void Heating_and_Protective_share_Systems_organizer_after_separate_AddComponent_calls() { @@ -114,6 +117,7 @@ public void Heating_and_Protective_share_Systems_organizer_after_separate_AddCom "it is a System substitution-group member and must be auto-wrapped."); } + /// Pins the behaviour expressed by the test name: programmatic device assembly produces systems at consistent depth. [Test] public void Programmatic_device_assembly_produces_systems_at_consistent_depth() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsRegressionTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsRegressionTests.cs index 78afd1668..c98885ced 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsRegressionTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsRegressionTests.cs @@ -31,6 +31,7 @@ namespace MTConnect.Tests.Common.SystemsOrganizer { + /// Pins the behaviour expressed by the test name: organizers systems regression tests. [TestFixture] [Category("OrganizersSystemsRegressionGuard")] public class OrganizersSystemsRegressionTests @@ -63,6 +64,7 @@ public class OrganizersSystemsRegressionTests "WorkEnvelope", }; + /// Pins the behaviour expressed by the test name: organizers systems matches pinned system substitution group. [Test] public void Organizers_Systems_matches_pinned_System_substitution_group() { @@ -73,6 +75,7 @@ public void Organizers_Systems_matches_pinned_System_substitution_group() "and `PinnedSystemMemberTypeIds` in this test."); } + /// Pins the behaviour expressed by the test name: every system described component subclass is in organizers systems. [Test] public void Every_System_described_Component_subclass_is_in_Organizers_Systems() { diff --git a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsTests.cs index 2ecb4fe5f..7726a2836 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/OrganizersSystemsTests.cs @@ -28,6 +28,7 @@ namespace MTConnect.Tests.Common.SystemsOrganizer { + /// Pins the behaviour expressed by the test name: organizers systems tests. [TestFixture] [Category("OrganizersSystemsSubstitutionGroup")] public class OrganizersSystemsTests @@ -64,6 +65,7 @@ public class OrganizersSystemsTests typeof(WorkEnvelopeComponent), }; + /// Gets or sets the known system members. public static IEnumerable KnownSystemMembers => SystemMemberComponentTypes.Select(t => GetTypeIdFromComponent(t)); @@ -74,12 +76,14 @@ public class OrganizersSystemsTests // `organizerType != ControllersComponent.TypeId` guard in // `Device.AddComponent()` and the carve-out invariant in // `OrganizersControllerCarveOutTests`. + /// Gets or sets the auto wrapped system member types. public static IEnumerable AutoWrappedSystemMemberTypes => SystemMemberComponentTypes; // Pairs the issue calls out plus a few representative peers; every // pair is expected to land at equal tree depth after // `Device.AddComponent()`. + /// Gets or sets the equal depth peer pairs. public static IEnumerable<(Type Left, Type Right)> EqualDepthPeerPairs => new[] { @@ -90,6 +94,8 @@ public class OrganizersSystemsTests (typeof(AirHandlerComponent), typeof(EnclosureComponent)), }; + /// Pins the behaviour expressed by the test name: system substitution group member listed in organizers systems. + /// The type id. [TestCaseSource(nameof(KnownSystemMembers))] public void System_substitution_group_member_listed_in_Organizers_Systems(string typeId) { @@ -103,9 +109,12 @@ public void System_substitution_group_member_listed_in_Organizers_Systems(string // `Controllers` organizer because `Controller` is not listed in // `Organizers.Systems`. The auto-wrapped members below all resolve // to `Systems`. + /// Gets or sets the auto wrapped system member type ids. public static IEnumerable AutoWrappedSystemMemberTypeIds => AutoWrappedSystemMemberTypes.Select(t => GetTypeIdFromComponent(t)); + /// Pins the behaviour expressed by the test name: get organizer type for auto wrapped system member returns systems. + /// The type id. [TestCaseSource(nameof(AutoWrappedSystemMemberTypeIds))] public void GetOrganizerType_for_auto_wrapped_system_member_returns_Systems(string typeId) { @@ -115,6 +124,7 @@ public void GetOrganizerType_for_auto_wrapped_system_member_returns_Systems(stri $"the auto-wrap path in `Device.AddComponent()` fires."); } + /// Pins the behaviour expressed by the test name: get organizer type for controller returns controllers not systems. [Test] public void GetOrganizerType_for_Controller_returns_Controllers_not_Systems() { @@ -126,6 +136,8 @@ public void GetOrganizerType_for_Controller_returns_Controllers_not_Systems() Is.EqualTo(ControllersComponent.TypeId)); } + /// Pins the behaviour expressed by the test name: peer system components sit at equal depth after add component. + /// The pair. [TestCaseSource(nameof(EqualDepthPeerPairs))] public void Peer_system_components_sit_at_equal_depth_after_AddComponent( (Type Left, Type Right) pair) @@ -143,6 +155,8 @@ public void Peer_system_components_sit_at_equal_depth_after_AddComponent( $"Got `{pair.Left.Name}` depth={leftDepth}, `{pair.Right.Name}` depth={rightDepth}."); } + /// Pins the behaviour expressed by the test name: auto wrapped system member lands under systems organizer. + /// The component type. [TestCaseSource(nameof(AutoWrappedSystemMemberTypes))] public void Auto_wrapped_system_member_lands_under_Systems_organizer(Type componentType) { diff --git a/tests/MTConnect.NET-Common-Tests/Headers/HeaderVersionFormattingCacheTests.cs b/tests/MTConnect.NET-Common-Tests/Headers/HeaderVersionFormattingCacheTests.cs index ef4e8d57c..05a76e0ea 100644 --- a/tests/MTConnect.NET-Common-Tests/Headers/HeaderVersionFormattingCacheTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Headers/HeaderVersionFormattingCacheTests.cs @@ -16,6 +16,7 @@ namespace MTConnect.Tests.Common.Headers { + /// Pins the behaviour expressed by the test name: header version formatting cache tests. [TestFixture] public class HeaderVersionFormattingCacheTests { @@ -35,6 +36,7 @@ private static string Invoke(MethodInfo formatter, Version version) return (string)formatter.Invoke(null, new object[] { version })!; } + /// Pins the behaviour expressed by the test name: format header version returns same string instance on repeated calls for same version. [Test] public void FormatHeaderVersion_returns_same_string_instance_on_repeated_calls_for_same_version() { @@ -48,6 +50,7 @@ public void FormatHeaderVersion_returns_same_string_instance_on_repeated_calls_f "Repeated calls with the same Version must return the cached string instance, not allocate a new one."); } + /// Pins the behaviour expressed by the test name: format header version returns same string instance for distinct but equal version instances. [Test] public void FormatHeaderVersion_returns_same_string_instance_for_distinct_but_equal_version_instances() { @@ -64,6 +67,7 @@ public void FormatHeaderVersion_returns_same_string_instance_for_distinct_but_eq "Cache must key on Version equality, not reference identity, so equal Version instances reuse the formatted string."); } + /// Pins the behaviour expressed by the test name: format header version caches independently per version. [Test] public void FormatHeaderVersion_caches_independently_per_version() { diff --git a/tests/MTConnect.NET-Common-Tests/Headers/HeaderVersionRegressionTests.cs b/tests/MTConnect.NET-Common-Tests/Headers/HeaderVersionRegressionTests.cs index 9de5ac6ed..1d9ba6afe 100644 --- a/tests/MTConnect.NET-Common-Tests/Headers/HeaderVersionRegressionTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Headers/HeaderVersionRegressionTests.cs @@ -26,6 +26,7 @@ namespace MTConnect.Tests.Common.Headers { + /// Pins the behaviour expressed by the test name: header version regression tests. [TestFixture] public class HeaderVersionRegressionTests { @@ -61,6 +62,8 @@ private static MTConnectAgentBroker BuildBroker(Version configuredVersion) return broker; } + /// Pins the behaviour expressed by the test name: devices header version equals configured mtconnect release. + /// The configured version. [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] public void Devices_header_version_equals_configured_mtconnect_release(Version configuredVersion) { @@ -75,6 +78,8 @@ public void Devices_header_version_equals_configured_mtconnect_release(Version c Is.EqualTo(ExpectedHeaderVersion(configuredVersion))); } + /// Pins the behaviour expressed by the test name: assets header version equals configured mtconnect release. + /// The configured version. [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] public void Assets_header_version_equals_configured_mtconnect_release(Version configuredVersion) { @@ -89,6 +94,8 @@ public void Assets_header_version_equals_configured_mtconnect_release(Version co Is.EqualTo(ExpectedHeaderVersion(configuredVersion))); } + /// Pins the behaviour expressed by the test name: error header version equals configured mtconnect release. + /// The configured version. [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] public void Error_header_version_equals_configured_mtconnect_release(Version configuredVersion) { @@ -102,6 +109,8 @@ public void Error_header_version_equals_configured_mtconnect_release(Version con Is.EqualTo(ExpectedHeaderVersion(configuredVersion))); } + /// Pins the behaviour expressed by the test name: devices header version equals configured release when passed explicitly. + /// The configured version. [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] public void Devices_header_version_equals_configured_release_when_passed_explicitly(Version configuredVersion) { @@ -119,6 +128,7 @@ public void Devices_header_version_equals_configured_release_when_passed_explici Is.EqualTo(ExpectedHeaderVersion(configuredVersion))); } + /// Pins the behaviour expressed by the test name: no response envelope emits the library assembly version. [Test] public void No_response_envelope_emits_the_library_assembly_version() { diff --git a/tests/MTConnect.NET-Common-Tests/Headers/HeaderXmlDocExampleVersionTests.cs b/tests/MTConnect.NET-Common-Tests/Headers/HeaderXmlDocExampleVersionTests.cs index 546dbf4e4..3cc02538a 100644 --- a/tests/MTConnect.NET-Common-Tests/Headers/HeaderXmlDocExampleVersionTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Headers/HeaderXmlDocExampleVersionTests.cs @@ -50,6 +50,8 @@ private static string FindRepoRoot() return string.Empty; } + /// Pins the behaviour expressed by the test name: header xmldoc example does not reference stale version 2 5. + /// The relative path. [TestCaseSource(nameof(HeaderFileRelativePaths))] public void Header_xmldoc_example_does_not_reference_stale_version_2_5(string relativePath) { diff --git a/tests/MTConnect.NET-Common-Tests/Interfaces/InterfaceDataItemSubTypesTests.cs b/tests/MTConnect.NET-Common-Tests/Interfaces/InterfaceDataItemSubTypesTests.cs index d045337b5..91c7694a1 100644 --- a/tests/MTConnect.NET-Common-Tests/Interfaces/InterfaceDataItemSubTypesTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Interfaces/InterfaceDataItemSubTypesTests.cs @@ -50,6 +50,8 @@ public class InterfaceDataItemSubTypesTests private static System.Collections.Generic.IEnumerable InterfaceDataItemTypes => _interfaceDataItemTypes; + /// Pins the behaviour expressed by the test name: interface data item exposes sub types enum. + /// The interface data item type. [Test] [TestCaseSource(nameof(InterfaceDataItemTypes))] public void Interface_DataItem_Exposes_SubTypes_Enum(Type interfaceDataItemType) @@ -62,6 +64,8 @@ public void Interface_DataItem_Exposes_SubTypes_Enum(Type interfaceDataItemType) $"{interfaceDataItemType.Name}.SubTypes must be an enum"); } + /// Pins the behaviour expressed by the test name: interface data item sub types contains request and response. + /// The interface data item type. [Test] [TestCaseSource(nameof(InterfaceDataItemTypes))] public void Interface_DataItem_SubTypes_Contains_Request_And_Response(Type interfaceDataItemType) diff --git a/tests/MTConnect.NET-Common-Tests/Observations/ObservationFactoryRuntimeTypeTests.cs b/tests/MTConnect.NET-Common-Tests/Observations/ObservationFactoryRuntimeTypeTests.cs index 48c22693c..ed9e93851 100644 --- a/tests/MTConnect.NET-Common-Tests/Observations/ObservationFactoryRuntimeTypeTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Observations/ObservationFactoryRuntimeTypeTests.cs @@ -40,6 +40,7 @@ public class ObservationFactoryRuntimeTypeTests { // ---- EventObservation.Create(string, DataItemRepresentation) ---- + /// Pins the behaviour expressed by the test name: event observation create m e s s a g e v a l u e returns message value observation. [Test] public void EventObservation_Create_MESSAGE_VALUE_returns_MessageValueObservation() { @@ -63,6 +64,7 @@ public void EventObservation_Create_MESSAGE_VALUE_returns_MessageValueObservatio // So we deliberately do NOT assert result.Type here. } + /// Pins the behaviour expressed by the test name: event observation create a s s e t c h a n g e d v a l u e returns asset changed value observation. [Test] public void EventObservation_Create_ASSET_CHANGED_VALUE_returns_AssetChangedValueObservation() { @@ -81,6 +83,7 @@ public void EventObservation_Create_ASSET_CHANGED_VALUE_returns_AssetChangedValu + "the hostile case for any key-format mismatch."); } + /// Pins the behaviour expressed by the test name: event observation create unknown type falls back to event value observation. [Test] public void EventObservation_Create_unknown_type_falls_back_to_EventValueObservation() { @@ -96,6 +99,7 @@ public void EventObservation_Create_unknown_type_falls_back_to_EventValueObserva "Unknown EVENT/VALUE types must land on the abstract carrier."); } + /// Pins the behaviour expressed by the test name: event observation create d a t a s e t returns event data set observation. [Test] public void EventObservation_Create_DATA_SET_returns_EventDataSetObservation() { @@ -112,6 +116,7 @@ public void EventObservation_Create_DATA_SET_returns_EventDataSetObservation() // ---- SampleObservation.Create(string, DataItemRepresentation) ---- + /// Pins the behaviour expressed by the test name: sample observation create v a l u e returns sample value observation. [Test] public void SampleObservation_Create_VALUE_returns_SampleValueObservation() { @@ -127,6 +132,7 @@ public void SampleObservation_Create_VALUE_returns_SampleValueObservation() "SAMPLE/VALUE must hydrate SampleValueObservation."); } + /// Pins the behaviour expressed by the test name: sample observation create d a t a s e t returns sample data set observation. [Test] public void SampleObservation_Create_DATA_SET_returns_SampleDataSetObservation() { @@ -138,6 +144,7 @@ public void SampleObservation_Create_DATA_SET_returns_SampleDataSetObservation() "SAMPLE/DATA_SET must hydrate SampleDataSetObservation."); } + /// Pins the behaviour expressed by the test name: sample observation create t a b l e returns sample table observation. [Test] public void SampleObservation_Create_TABLE_returns_SampleTableObservation() { @@ -149,6 +156,7 @@ public void SampleObservation_Create_TABLE_returns_SampleTableObservation() "SAMPLE/TABLE must hydrate SampleTableObservation."); } + /// Pins the behaviour expressed by the test name: sample observation create t i m e s e r i e s returns sample time series observation. [Test] public void SampleObservation_Create_TIME_SERIES_returns_SampleTimeSeriesObservation() { @@ -162,6 +170,7 @@ public void SampleObservation_Create_TIME_SERIES_returns_SampleTimeSeriesObserva // ---- ConditionObservation.Create(string, DataItemRepresentation) - + /// Pins the behaviour expressed by the test name: condition observation create returns condition observation carrier. [Test] public void ConditionObservation_Create_returns_ConditionObservation_carrier() { diff --git a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedAssetsCoverageTests.cs b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedAssetsCoverageTests.cs index 6ecfe73df..bbb9c5638 100644 --- a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedAssetsCoverageTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedAssetsCoverageTests.cs @@ -33,6 +33,7 @@ namespace MTConnect.NET_Common_Tests.Reflection // - Prose: docs.mtconnect.org "Part 4.0 - Assets Information Model" // §"Asset" — defines the asset-id / timestamp / deviceUuid // wire-shape contract. + /// Pins the behaviour expressed by the test name: regenerated assets coverage tests. [TestFixture] public class RegeneratedAssetsCoverageTests { @@ -62,6 +63,8 @@ private static IEnumerable EnumerateAssetSubtypes() .OrderBy(t => t.FullName, StringComparer.Ordinal); } + /// Runs the asset subtypes operation. + /// The result of the operation. public static IEnumerable AssetSubtypes() { foreach (var type in EnumerateAssetSubtypes()) @@ -71,6 +74,7 @@ public static IEnumerable AssetSubtypes() } } + /// Pins the behaviour expressed by the test name: catalogue enumerates at least one asset subtype. [Test] public void Catalogue_enumerates_at_least_one_asset_subtype() { @@ -81,6 +85,8 @@ public void Catalogue_enumerates_at_least_one_asset_subtype() "MTConnect.Assets produced zero concrete subtypes — regenerator regression?"); } + /// Pins the behaviour expressed by the test name: asset subtype is constructible. + /// The type. [Test] [TestCaseSource(nameof(AssetSubtypes))] public void Asset_subtype_is_constructible(Type type) @@ -93,6 +99,8 @@ public void Asset_subtype_is_constructible(Type type) $"{type.FullName} parameterless ctor returned null"); } + /// Pins the behaviour expressed by the test name: asset subtype inherits asset id round trip. + /// The type. [Test] [TestCaseSource(nameof(AssetSubtypes))] public void Asset_subtype_inherits_AssetId_round_trip(Type type) @@ -109,6 +117,8 @@ public void Asset_subtype_inherits_AssetId_round_trip(Type type) $"{type.FullName}.AssetId did not round-trip"); } + /// Pins the behaviour expressed by the test name: asset subtype inherits device uuid round trip. + /// The type. [Test] [TestCaseSource(nameof(AssetSubtypes))] public void Asset_subtype_inherits_DeviceUuid_round_trip(Type type) @@ -121,6 +131,8 @@ public void Asset_subtype_inherits_DeviceUuid_round_trip(Type type) $"{type.FullName}.DeviceUuid did not round-trip"); } + /// Pins the behaviour expressed by the test name: asset subtype inherits timestamp round trip. + /// The type. [Test] [TestCaseSource(nameof(AssetSubtypes))] public void Asset_subtype_inherits_Timestamp_round_trip(Type type) @@ -133,6 +145,8 @@ public void Asset_subtype_inherits_Timestamp_round_trip(Type type) $"{type.FullName}.Timestamp did not round-trip"); } + /// Pins the behaviour expressed by the test name: asset subtype exposes description text field. + /// The type. [Test] [TestCaseSource(nameof(AssetSubtypes))] public void Asset_subtype_exposes_DescriptionText_field(Type type) diff --git a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedComponentsCoverageTests.cs b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedComponentsCoverageTests.cs index 63377b54e..960f3e544 100644 --- a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedComponentsCoverageTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedComponentsCoverageTests.cs @@ -35,6 +35,7 @@ namespace MTConnect.NET_Common_Tests.Reflection // - Prose: docs.mtconnect.org "Part 2.0 - Devices Information Model" // §"Component" — defines the Component / Composition / Device // role hierarchy. + /// Pins the behaviour expressed by the test name: regenerated components coverage tests. [TestFixture] public class RegeneratedComponentsCoverageTests { @@ -51,6 +52,8 @@ private static IEnumerable EnumerateComponentSubtypes() .OrderBy(t => t.FullName, StringComparer.Ordinal); } + /// Runs the component subtypes operation. + /// The result of the operation. public static IEnumerable ComponentSubtypes() { foreach (var type in EnumerateComponentSubtypes()) @@ -60,6 +63,7 @@ public static IEnumerable ComponentSubtypes() } } + /// Pins the behaviour expressed by the test name: catalogue enumerates at least one component subtype. [Test] public void Catalogue_enumerates_at_least_one_component_subtype() { @@ -70,6 +74,8 @@ public void Catalogue_enumerates_at_least_one_component_subtype() "MTConnect.Devices.Components produced fewer than 50 concrete subtypes — regenerator regression?"); } + /// Pins the behaviour expressed by the test name: component subtype exposes non empty type id. + /// The type. [Test] [TestCaseSource(nameof(ComponentSubtypes))] public void Component_subtype_exposes_non_empty_TypeId(Type type) @@ -87,6 +93,8 @@ public void Component_subtype_exposes_non_empty_TypeId(Type type) $"{type.FullName}.TypeId is null or empty"); } + /// Pins the behaviour expressed by the test name: constructed component subtype carries type from const. + /// The type. [Test] [TestCaseSource(nameof(ComponentSubtypes))] public void Constructed_Component_subtype_carries_Type_from_const(Type type) diff --git a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedConfigurationsCoverageTests.cs b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedConfigurationsCoverageTests.cs index 58e8378ed..51e9f45d2 100644 --- a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedConfigurationsCoverageTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedConfigurationsCoverageTests.cs @@ -36,6 +36,7 @@ namespace MTConnect.NET_Common_Tests.Reflection // of a Component. // - Prose: docs.mtconnect.org "Part 2.0 - Devices Information Model" // §"Configuration" — defines the Configuration role. + /// Pins the behaviour expressed by the test name: regenerated configurations coverage tests. [TestFixture] public class RegeneratedConfigurationsCoverageTests { @@ -51,6 +52,8 @@ private static IEnumerable EnumerateConfigurationSubtypes() .OrderBy(t => t.FullName, StringComparer.Ordinal); } + /// Runs the configuration subtypes operation. + /// The result of the operation. public static IEnumerable ConfigurationSubtypes() { foreach (var type in EnumerateConfigurationSubtypes()) @@ -60,6 +63,7 @@ public static IEnumerable ConfigurationSubtypes() } } + /// Pins the behaviour expressed by the test name: catalogue enumerates at least one configuration subtype. [Test] public void Catalogue_enumerates_at_least_one_configuration_subtype() { @@ -68,6 +72,8 @@ public void Catalogue_enumerates_at_least_one_configuration_subtype() "MTConnect.Devices.Configurations produced fewer than 10 concrete subtypes — regenerator regression?"); } + /// Pins the behaviour expressed by the test name: configuration subtype is constructible. + /// The type. [Test] [TestCaseSource(nameof(ConfigurationSubtypes))] public void Configuration_subtype_is_constructible(Type type) @@ -80,6 +86,8 @@ public void Configuration_subtype_is_constructible(Type type) $"{type.FullName} parameterless ctor returned null"); } + /// Pins the behaviour expressed by the test name: configuration subtype string properties round trip. + /// The type. [Test] [TestCaseSource(nameof(ConfigurationSubtypes))] public void Configuration_subtype_string_properties_round_trip(Type type) diff --git a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedDataItemsCoverageTests.cs b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedDataItemsCoverageTests.cs index d026147c6..a3adf054a 100644 --- a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedDataItemsCoverageTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedDataItemsCoverageTests.cs @@ -33,6 +33,7 @@ namespace MTConnect.NET_Common_Tests.Reflection // — defines the wire-shape constraint on the type+category pair. // - Prose: docs.mtconnect.org "Part 2.0 - Devices Information Model" // §"DataItem" — defines the SAMPLE / EVENT / CONDITION semantics. + /// Pins the behaviour expressed by the test name: regenerated data items coverage tests. [TestFixture] public class RegeneratedDataItemsCoverageTests { @@ -49,6 +50,8 @@ private static IEnumerable EnumerateDataItemSubtypes() .OrderBy(t => t.FullName, StringComparer.Ordinal); } + /// Runs the data item subtypes operation. + /// The result of the operation. public static IEnumerable DataItemSubtypes() { foreach (var type in EnumerateDataItemSubtypes()) @@ -58,6 +61,7 @@ public static IEnumerable DataItemSubtypes() } } + /// Pins the behaviour expressed by the test name: catalogue enumerates at least one data item subtype. [Test] public void Catalogue_enumerates_at_least_one_data_item_subtype() { @@ -68,6 +72,8 @@ public void Catalogue_enumerates_at_least_one_data_item_subtype() "MTConnect.Devices.DataItems produced fewer than 100 concrete subtypes — regenerator regression?"); } + /// Pins the behaviour expressed by the test name: data item subtype exposes non empty type id. + /// The type. [Test] [TestCaseSource(nameof(DataItemSubtypes))] public void DataItem_subtype_exposes_non_empty_TypeId(Type type) @@ -85,6 +91,8 @@ public void DataItem_subtype_exposes_non_empty_TypeId(Type type) $"{type.FullName}.TypeId is null or empty"); } + /// Pins the behaviour expressed by the test name: data item subtype type id is upper snake case. + /// The type. [Test] [TestCaseSource(nameof(DataItemSubtypes))] public void DataItem_subtype_TypeId_is_upper_snake_case(Type type) @@ -102,6 +110,8 @@ public void DataItem_subtype_TypeId_is_upper_snake_case(Type type) $"{type.FullName}.TypeId = \"{value}\" violates the upper-snake-case wire-shape rule"); } + /// Pins the behaviour expressed by the test name: data item subtype exposes known category id. + /// The type. [Test] [TestCaseSource(nameof(DataItemSubtypes))] public void DataItem_subtype_exposes_known_CategoryId(Type type) @@ -125,6 +135,8 @@ public void DataItem_subtype_exposes_known_CategoryId(Type type) $"{type.FullName}.CategoryId = {category} is not one of SAMPLE / EVENT / CONDITION"); } + /// Pins the behaviour expressed by the test name: constructed data item subtype carries category and type from const pair. + /// The type. [Test] [TestCaseSource(nameof(DataItemSubtypes))] public void Constructed_DataItem_subtype_carries_category_and_type_from_const_pair(Type type) @@ -150,6 +162,7 @@ public void Constructed_DataItem_subtype_carries_category_and_type_from_const_pa $"{type.FullName} default ctor did not wire Category from CategoryId"); } + /// Pins the behaviour expressed by the test name: data item subtype with unknown type id string is rejected at lookup. [Test] public void DataItem_subtype_with_unknown_TypeId_string_is_rejected_at_lookup() { diff --git a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedTypesCoverageTests.cs b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedTypesCoverageTests.cs index 91e0b2822..7c26b1c78 100644 --- a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedTypesCoverageTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedTypesCoverageTests.cs @@ -35,6 +35,7 @@ namespace MTConnect.NET_Common_Tests.Reflection // assembly with public-type filters. New SysML regenerations therefore // pick up new coverage automatically without any test edit — that is the // mechanism by which "every public regenerated type" is gated. + /// Pins the behaviour expressed by the test name: regenerated types coverage tests. [TestFixture] public class RegeneratedTypesCoverageTests { @@ -88,6 +89,8 @@ private static IEnumerable EnumeratePublicRegeneratedTypes() .OrderBy(t => t.FullName, StringComparer.Ordinal); } + /// Runs the constructible types operation. + /// The result of the operation. public static IEnumerable ConstructibleTypes() { foreach (var type in EnumeratePublicRegeneratedTypes()) @@ -116,6 +119,8 @@ public static IEnumerable ConstructibleTypes() } } + /// Runs the round trippable types operation. + /// The result of the operation. public static IEnumerable RoundTrippableTypes() { foreach (var type in EnumeratePublicRegeneratedTypes()) @@ -145,6 +150,8 @@ public static IEnumerable RoundTrippableTypes() } } + /// Runs the types with description text operation. + /// The result of the operation. public static IEnumerable TypesWithDescriptionText() { foreach (var type in EnumeratePublicRegeneratedTypes()) @@ -173,6 +180,7 @@ public static IEnumerable TypesWithDescriptionText() "MTConnect.Assets.Fixture.FixtureAsset", }; + /// Pins the behaviour expressed by the test name: known empty description types still emit an empty string. [Test] public void Known_empty_description_types_still_emit_an_empty_string() { @@ -198,6 +206,8 @@ public void Known_empty_description_types_still_emit_an_empty_string() } } + /// Pins the behaviour expressed by the test name: type can be constructed. + /// The type. [Test] [TestCaseSource(nameof(ConstructibleTypes))] public void Type_can_be_constructed(Type type) @@ -215,6 +225,8 @@ public void Type_can_be_constructed(Type type) $"{type.FullName} parameterless ctor returned null"); } + /// Pins the behaviour expressed by the test name: type round trips default property values. + /// The type. [Test] [TestCaseSource(nameof(RoundTrippableTypes))] public void Type_round_trips_default_property_values(Type type) @@ -273,6 +285,8 @@ public void Type_round_trips_default_property_values(Type type) } } + /// Pins the behaviour expressed by the test name: type has non empty description. + /// The type. [Test] [TestCaseSource(nameof(TypesWithDescriptionText))] public void Type_has_non_empty_description(Type type) @@ -286,6 +300,7 @@ public void Type_has_non_empty_description(Type type) // Smoke-test the catalog itself so the parametric sweep cannot // silently shrink to zero (e.g. namespace rename that drops every // anchor). At least one constructible type must exist. + /// Pins the behaviour expressed by the test name: catalog enumerates at least one type per namespace. [Test] public void Catalog_enumerates_at_least_one_type_per_namespace() { @@ -423,9 +438,12 @@ private static string SanitizeForTestName(string name) // demands one is a generator-side defect (see plan // 13-generator-improvements). Such defects are tracked there, NOT // patched in by silencing the parametric sweep. + /// Pins the behaviour expressed by the test name: regenerated type version annotation tests. [TestFixture] public class RegeneratedTypeVersionAnnotationTests { + /// Runs the types with minimum version override operation. + /// The result of the operation. public static IEnumerable TypesWithMinimumVersionOverride() { foreach (var type in EnumeratePublicRegeneratedTypes()) @@ -476,6 +494,8 @@ public static IEnumerable TypesWithMinimumVersionOverride() } } + /// Runs the types with maximum version override operation. + /// The result of the operation. public static IEnumerable TypesWithMaximumVersionOverride() { foreach (var type in EnumeratePublicRegeneratedTypes()) @@ -531,6 +551,8 @@ public static IEnumerable TypesWithMaximumVersionOverride() } } + /// Pins the behaviour expressed by the test name: minimum version resolves to an advertised version. + /// The type. [Test] [TestCaseSource(nameof(TypesWithMinimumVersionOverride))] public void MinimumVersion_resolves_to_an_advertised_version(Type type) @@ -547,6 +569,8 @@ public void MinimumVersion_resolves_to_an_advertised_version(Type type) $"{type.FullName}.MinimumVersion = {value} is not one of MTConnectVersions's advertised constants"); } + /// Pins the behaviour expressed by the test name: maximum version resolves to an advertised version. + /// The type. [Test] [TestCaseSource(nameof(TypesWithMaximumVersionOverride))] public void MaximumVersion_resolves_to_an_advertised_version(Type type) diff --git a/tests/MTConnect.NET-Common-Tests/Regressions/DeviceComponentDefaultsRegressionTests.cs b/tests/MTConnect.NET-Common-Tests/Regressions/DeviceComponentDefaultsRegressionTests.cs index 93c3b545f..2822a738c 100644 --- a/tests/MTConnect.NET-Common-Tests/Regressions/DeviceComponentDefaultsRegressionTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Regressions/DeviceComponentDefaultsRegressionTests.cs @@ -27,6 +27,7 @@ public class DeviceComponentDefaultsRegressionTests { // ---- Device ------------------------------------------------ + /// Pins the behaviour expressed by the test name: device default constructor leaves identity fields null. [Test] public void Device_default_constructor_leaves_identity_fields_null() { @@ -39,6 +40,7 @@ public void Device_default_constructor_leaves_identity_fields_null() }); } + /// Pins the behaviour expressed by the test name: agent default constructor leaves identity fields null. [Test] public void Agent_default_constructor_leaves_identity_fields_null() { @@ -51,6 +53,7 @@ public void Agent_default_constructor_leaves_identity_fields_null() }); } + /// Pins the behaviour expressed by the test name: sequential default devices share null uuid. [Test] public void Sequential_default_Devices_share_null_Uuid() { @@ -63,6 +66,7 @@ public void Sequential_default_Devices_share_null_Uuid() Assert.That(second.Uuid, Is.Null); } + /// Pins the behaviour expressed by the test name: object initializer continues to set device identity. [Test] public void Object_initializer_continues_to_set_Device_identity() { @@ -77,6 +81,7 @@ public void Object_initializer_continues_to_set_Device_identity() // ---- Reflection guard -------------------------------------- + /// Pins the behaviour expressed by the test name: no device subclass default constructor back fills identity. [Test] public void No_Device_subclass_default_constructor_back_fills_identity() { @@ -101,6 +106,7 @@ public void No_Device_subclass_default_constructor_back_fills_identity() Assert.That(failures, Is.Empty, string.Join(Environment.NewLine, failures)); } + /// Pins the behaviour expressed by the test name: no component subclass default constructor back fills name. [Test] public void No_Component_subclass_default_constructor_back_fills_Name() { @@ -125,6 +131,7 @@ public void No_Component_subclass_default_constructor_back_fills_Name() Assert.That(failures, Is.Empty, string.Join(Environment.NewLine, failures)); } + /// Pins the behaviour expressed by the test name: reflection guard walks a meaningful set of component subclasses. [Test] public void Reflection_guard_walks_a_meaningful_set_of_Component_subclasses() { diff --git a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/MTConnectVersionsTests.cs b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/MTConnectVersionsTests.cs index 5167bb337..b4799004f 100644 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/MTConnectVersionsTests.cs +++ b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/MTConnectVersionsTests.cs @@ -17,12 +17,14 @@ namespace MTConnect.NET_Common_Tests.V2_6_V2_7 // - Prose: MTConnect Standard `Part_1.0_Overview_v2.7.pdf` section 1 "Versioning" // (the document numbering scheme — v1.0 through v2.7 with v1.9 // intentionally skipped — is described here.) + /// Pins the behaviour expressed by the test name: m t connect versions tests. [TestFixture] public class MTConnectVersionsTests { // Source: MTConnect SysML model, tag v2.6. // The model's version-list element introduces 2.6 between 2.5 and (later) // 2.7 with no in-between fractional versions. + /// Pins the behaviour expressed by the test name: version26 constant equals 2 6. [Test] public void Version26_constant_equals_2_6() { @@ -30,6 +32,7 @@ public void Version26_constant_equals_2_6() } // Source: MTConnect SysML model, tag v2.7. + /// Pins the behaviour expressed by the test name: version27 constant equals 2 7. [Test] public void Version27_constant_equals_2_7() { @@ -37,6 +40,7 @@ public void Version27_constant_equals_2_7() } // Locks Max to Version27 against accidental rollback. + /// Pins the behaviour expressed by the test name: max equals version27. [Test] public void Max_equals_Version27() { @@ -48,6 +52,7 @@ public void Max_equals_Version27() // confirmed by the absence of an XMI tag `v1.9` in // `mtconnect/mtconnect_sysml_model` (tags: v2.5 b61907fb78, // v2.6 08185447bf, v2.7 25796ac591). + /// Pins the behaviour expressed by the test name: every published version constant is distinct and monotonic. [Test] public void Every_published_version_constant_is_distinct_and_monotonic() { @@ -81,6 +86,7 @@ public void Every_published_version_constant_is_distinct_and_monotonic() // Pin that no `Version19` constant exists. Asserts on the named field — // silent insertion would invalidate downstream matrices. // Source: MTConnect SysML model tag list — no `v1.9` tag. + /// Pins the behaviour expressed by the test name: version19 field does not exist. [Test] public void Version19_field_does_not_exist() { diff --git a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_6ComponentAndEnumTests.cs b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_6ComponentAndEnumTests.cs index 240b50f0b..bcecc8dab 100644 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_6ComponentAndEnumTests.cs +++ b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_6ComponentAndEnumTests.cs @@ -17,11 +17,13 @@ namespace MTConnect.NET_Common_Tests.V2_6_V2_7 // - Prose: MTConnect Standard Part_3.0_Devices_v2.6 // section 3.4.18 "CuttingTorch" / section 3.4.21 "Electrode" // section 4.7.2.5 MediaType (introduces QIF_MBD) + /// Pins the behaviour expressed by the test name: v2 6 component and enum tests. [TestFixture] public class V2_6ComponentAndEnumTests { // Source: XMI v2.6 UML `CuttingTorch` (Component Types); XSD v2.6 // ``. + /// Pins the behaviour expressed by the test name: cutting torch component constructs with correct type. [Test] public void CuttingTorchComponent_constructs_with_correct_type() { @@ -34,6 +36,7 @@ public void CuttingTorchComponent_constructs_with_correct_type() // Source: XMI v2.6 UML `Electrode` (Component Types); XSD v2.6 // ``. + /// Pins the behaviour expressed by the test name: electrode component constructs with correct type. [Test] public void ElectrodeComponent_constructs_with_correct_type() { @@ -48,6 +51,7 @@ public void ElectrodeComponent_constructs_with_correct_type() // QIF_MBD inside the MediaType simpleType enumeration. Prose // Part_3.0_Devices_v2.6 section 4.7.2.5 introduces "ISO 10303 QIF model-based // design" as the rationale. + /// Pins the behaviour expressed by the test name: media type q i f m b d value present in v2 6. [Test] public void MediaType_QIF_MBD_value_present_in_v2_6() { diff --git a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_6DataItemTypeTests.cs b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_6DataItemTypeTests.cs index 7486c0d12..1919e9d1d 100644 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_6DataItemTypeTests.cs +++ b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_6DataItemTypeTests.cs @@ -18,11 +18,13 @@ namespace MTConnect.NET_Common_Tests.V2_6_V2_7 // - Prose: MTConnect Standard Part_2.0_Streams_v2.6 section 11.5 "Asset events" // (clarifies the v2.5 → v2.6 split — `AssetChanged` narrowed to // changes only; `AssetAdded` introduced for additions.) + /// Pins the behaviour expressed by the test name: v2 6 data item type tests. [TestFixture] public class V2_6DataItemTypeTests { // Source: XMI v2.6 UML class `AssetAddedDataItem`; XSD v2.6 enum `EventEnum` // value `ASSET_ADDED`. + /// Pins the behaviour expressed by the test name: asset added data item constructs with event metadata. [Test] public void AssetAddedDataItem_constructs_with_event_metadata() { @@ -36,6 +38,7 @@ public void AssetAddedDataItem_constructs_with_event_metadata() } // Source: XMI v2.6 — `DataItem.id` formation rule via parent device. + /// Pins the behaviour expressed by the test name: asset added data item with device id produces qualified id. [Test] public void AssetAddedDataItem_with_deviceId_produces_qualified_id() { @@ -47,6 +50,7 @@ public void AssetAddedDataItem_with_deviceId_produces_qualified_id() // Source: XMI v2.6 UML class `AssociatedAssetIdDataItem`; XSD v2.6 // EventEnum value `ASSOCIATED_ASSET_ID`. + /// Pins the behaviour expressed by the test name: associated asset id data item constructs with event metadata. [Test] public void AssociatedAssetIdDataItem_constructs_with_event_metadata() { @@ -59,6 +63,7 @@ public void AssociatedAssetIdDataItem_constructs_with_event_metadata() } // Source: XMI v2.6 — generalization of `AssetAddedDataItem` is `DataItem`. + /// Pins the behaviour expressed by the test name: asset added data item inherits from data item. [Test] public void AssetAddedDataItem_inherits_from_DataItem() { @@ -66,6 +71,7 @@ public void AssetAddedDataItem_inherits_from_DataItem() } // Source: XMI v2.6 — generalization of `AssociatedAssetIdDataItem` is `DataItem`. + /// Pins the behaviour expressed by the test name: associated asset id data item inherits from data item. [Test] public void AssociatedAssetIdDataItem_inherits_from_DataItem() { @@ -75,6 +81,7 @@ public void AssociatedAssetIdDataItem_inherits_from_DataItem() // Source: XMI v2.6 description on `AssetChangedDataItem` (was "added or // changed" in v2.5; now "changed" only). Prose confirms in // Part_2.0_Streams_v2.6 section 11.5. + /// Pins the behaviour expressed by the test name: asset changed data item description narrowed in v2 6. [Test] public void AssetChangedDataItem_description_narrowed_in_v2_6() { diff --git a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7ComponentTests.cs b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7ComponentTests.cs index 9f27b53bd..1e61a0008 100644 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7ComponentTests.cs +++ b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7ComponentTests.cs @@ -13,9 +13,11 @@ namespace MTConnect.NET_Common_Tests.V2_6_V2_7 // (each TypeId appears in the ComponentType enumeration). // - Prose: MTConnect Standard Part_2.0_Devices_v2.7 section 7 "Component // types" — describes intended use of each Component subclass. + /// Pins the behaviour expressed by the test name: v2 7 component tests. [TestFixture] public class V2_7ComponentTests { + /// Pins the behaviour expressed by the test name: pin tool component constructs with correct type. [Test] public void PinToolComponent_constructs_with_correct_type() { @@ -26,6 +28,7 @@ public void PinToolComponent_constructs_with_correct_type() Assert.That(PinToolComponent.NameId, Is.EqualTo("pinTool")); } + /// Pins the behaviour expressed by the test name: tool holder component constructs with correct type. [Test] public void ToolHolderComponent_constructs_with_correct_type() { diff --git a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7ConfigurationDataSetTests.cs b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7ConfigurationDataSetTests.cs index 2d6cbbe73..10503fa66 100644 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7ConfigurationDataSetTests.cs +++ b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7ConfigurationDataSetTests.cs @@ -23,12 +23,14 @@ namespace MTConnect.NET_Common_Tests.V2_6_V2_7 // - Prose: MTConnect Standard Part_2.0_Devices_v2.7 section 10 "Configuration" // — describes how Component-level Configuration carries the // geometric primitives that locate a Component in space. + /// Pins the behaviour expressed by the test name: v2 7 configuration data set tests. [TestFixture] public class V2_7ConfigurationDataSetTests { // The DataSet base (grafted from Observation.Representations via the // universal resolver) compiles, instantiates, and surfaces its // const description. + /// Pins the behaviour expressed by the test name: data set base constructs and implements i data set. [Test] public void DataSet_base_constructs_and_implements_IDataSet() { @@ -42,6 +44,7 @@ public void DataSet_base_constructs_and_implements_IDataSet() // not the concrete DataSet base — *DataSet types polymorphically // extend their Abstract base, gaining IDataSet as a marker // interface so XML/JSON serialisers can narrow on it). + /// Pins the behaviour expressed by the test name: axis data set has xyz fields and implements i data set. [Test] public void AxisDataSet_has_xyz_fields_and_implements_IDataSet() { @@ -53,6 +56,7 @@ public void AxisDataSet_has_xyz_fields_and_implements_IDataSet() Assert.That(a.Z, Is.EqualTo(3.0)); } + /// Pins the behaviour expressed by the test name: origin data set has xyz fields and implements i data set. [Test] public void OriginDataSet_has_xyz_fields_and_implements_IDataSet() { @@ -61,6 +65,7 @@ public void OriginDataSet_has_xyz_fields_and_implements_IDataSet() Assert.That(o, Is.InstanceOf()); } + /// Pins the behaviour expressed by the test name: rotation data set has abc fields and implements i data set. [Test] public void RotationDataSet_has_abc_fields_and_implements_IDataSet() { @@ -70,6 +75,7 @@ public void RotationDataSet_has_abc_fields_and_implements_IDataSet() Assert.That(r, Is.InstanceOf()); } + /// Pins the behaviour expressed by the test name: scale data set implements i data set. [Test] public void ScaleDataSet_implements_IDataSet() { @@ -78,6 +84,7 @@ public void ScaleDataSet_implements_IDataSet() Assert.That(s, Is.InstanceOf()); } + /// Pins the behaviour expressed by the test name: translation data set implements i data set. [Test] public void TranslationDataSet_implements_IDataSet() { @@ -88,6 +95,7 @@ public void TranslationDataSet_implements_IDataSet() // Concrete (non-DataSet) representations of the same primitives, also // landed in v2.7 alongside their DataSet siblings. + /// Pins the behaviour expressed by the test name: axis inherits abstract axis and constructs. [Test] public void Axis_inherits_AbstractAxis_and_constructs() { @@ -97,6 +105,7 @@ public void Axis_inherits_AbstractAxis_and_constructs() Assert.That(a.Value, Is.EqualTo("X")); } + /// Pins the behaviour expressed by the test name: origin inherits abstract origin. [Test] public void Origin_inherits_AbstractOrigin() { @@ -105,18 +114,21 @@ public void Origin_inherits_AbstractOrigin() Assert.That(o, Is.InstanceOf()); } + /// Pins the behaviour expressed by the test name: rotation inherits abstract rotation. [Test] public void Rotation_inherits_AbstractRotation() { Assert.That(new Rotation(), Is.InstanceOf()); } + /// Pins the behaviour expressed by the test name: scale inherits abstract scale. [Test] public void Scale_inherits_AbstractScale() { Assert.That(new Scale(), Is.InstanceOf()); } + /// Pins the behaviour expressed by the test name: translation inherits abstract translation. [Test] public void Translation_inherits_AbstractTranslation() { @@ -125,30 +137,35 @@ public void Translation_inherits_AbstractTranslation() // The Abstract* bases are abstract — verify so a future regen that // accidentally drops the abstract modifier trips here. + /// Pins the behaviour expressed by the test name: abstract axis is abstract. [Test] public void AbstractAxis_is_abstract() { Assert.That(typeof(AbstractAxis).IsAbstract, Is.True); } + /// Pins the behaviour expressed by the test name: abstract origin is abstract. [Test] public void AbstractOrigin_is_abstract() { Assert.That(typeof(AbstractOrigin).IsAbstract, Is.True); } + /// Pins the behaviour expressed by the test name: abstract rotation is abstract. [Test] public void AbstractRotation_is_abstract() { Assert.That(typeof(AbstractRotation).IsAbstract, Is.True); } + /// Pins the behaviour expressed by the test name: abstract scale is abstract. [Test] public void AbstractScale_is_abstract() { Assert.That(typeof(AbstractScale).IsAbstract, Is.True); } + /// Pins the behaviour expressed by the test name: abstract translation is abstract. [Test] public void AbstractTranslation_is_abstract() { diff --git a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7DataItemTypeTests.cs b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7DataItemTypeTests.cs index 08f9ba794..0faef2fc1 100644 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7DataItemTypeTests.cs +++ b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7DataItemTypeTests.cs @@ -22,6 +22,7 @@ namespace MTConnect.NET_Common_Tests.V2_6_V2_7 // enumerations.) // - Prose: MTConnect Standard Part_2.0_Streams_v2.7 section 11/section 13 "Event/Sample // types" — describes intended use of each type. + /// Pins the behaviour expressed by the test name: v2 7 data item type tests. [TestFixture] public class V2_7DataItemTypeTests { @@ -29,6 +30,10 @@ public class V2_7DataItemTypeTests // authority. Several types that look "measurement-y" (SwingAngle, Depth, // etc.) are EVENT in the spec rather than SAMPLE; locking them so a // future regen drift is caught immediately. + /// Pins the behaviour expressed by the test name: v2 7 data item constructs with correct metadata. + /// The data item type. + /// The expected type id. + /// The expected category. [TestCase(typeof(BindingStateDataItem), "BINDING_STATE", DataItemCategory.EVENT)] [TestCase(typeof(DepthDataItem), "DEPTH", DataItemCategory.EVENT)] [TestCase(typeof(FixtureAssetIdDataItem), "FIXTURE_ASSET_ID", DataItemCategory.EVENT)] diff --git a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7SampleObservationTests.cs b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7SampleObservationTests.cs index bc44576a8..bc906c56b 100644 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7SampleObservationTests.cs +++ b/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7SampleObservationTests.cs @@ -25,6 +25,7 @@ namespace MTConnect.NET_Common_Tests.V2_6_V2_7 // observation through the library's `SampleValueObservation` carrier and // confirm the (DataItem, Observation) pair carries the v2.7 type metadata // intact. + /// Pins the behaviour expressed by the test name: v2 7 sample observation tests. [TestFixture] public class V2_7SampleObservationTests { @@ -34,6 +35,7 @@ public class V2_7SampleObservationTests // and reading back the value. If the library starts dropping the link // between the DataItem's TypeId and the observation's reported type, // this test catches it. + /// Pins the behaviour expressed by the test name: water hardness sample observation round trip. [Test] public void WaterHardness_sample_observation_round_trip() { From 81f3ab25742da5d5cceb0299e82c01149c8b5a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:28:22 +0200 Subject: [PATCH 10/29] docs(xml-tests): author XML doc comments on test surface --- ...ConfigurationPolymorphicAxisRoundTripTests.cs | 13 +++++++++++++ ...nfigurationPolymorphicOriginRoundTripTests.cs | 16 ++++++++++++++++ ...igurationPolymorphicRotationRoundTripTests.cs | 12 ++++++++++++ ...onfigurationPolymorphicScaleRoundTripTests.cs | 14 ++++++++++++++ ...rationPolymorphicTranslationRoundTripTests.cs | 12 ++++++++++++ .../CoordinateSystemDescriptionWriteTests.cs | 6 ++++++ .../Devices/DeviceCtorDefaultsWireShapeTests.cs | 3 +++ .../Devices/DeviceLoad.cs | 4 ++++ .../Devices/XmlDataItemEmptyNameOmissionTests.cs | 3 +++ .../Headers/HeaderVersionXmlRoundTripTests.cs | 5 +++++ tests/MTConnect.NET-XML-Tests/Streams/Current.cs | 2 ++ .../XmlStreamsResponseDocumentTests.cs | 2 ++ 12 files changed, 92 insertions(+) diff --git a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs index f0af1773d..031fbca25 100644 --- a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs +++ b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs @@ -33,6 +33,7 @@ public class ConfigurationPolymorphicAxisRoundTripTests { // ---------------- positive: simple Axis ---------------- + /// Pins the behaviour expressed by the test name: simple axis serialises to text element. [Test] public void Simple_Axis_serialises_to_text_element() { @@ -50,6 +51,7 @@ public void Simple_Axis_serialises_to_text_element() Assert.That(xml, Does.Not.Contain("Pins the behaviour expressed by the test name: simple axis deserialises to i axis. [Test] public void Simple_Axis_deserialises_to_IAxis() { @@ -67,6 +69,7 @@ public void Simple_Axis_deserialises_to_IAxis() // ---------------- positive: AxisDataSet ---------------- + /// Pins the behaviour expressed by the test name: axis data set serialises to keyed entries. [Test] public void AxisDataSet_serialises_to_keyed_entries() { @@ -87,6 +90,7 @@ public void AxisDataSet_serialises_to_keyed_entries() Assert.That(xml, Does.Not.Contain("")); } + /// Pins the behaviour expressed by the test name: axis data set deserialises to i axis data set. [Test] public void AxisDataSet_deserialises_to_IAxisDataSet() { @@ -113,6 +117,7 @@ public void AxisDataSet_deserialises_to_IAxisDataSet() // the XsdLoadStrict category so they participate in the opt-in // strict-load sweep once an XSD 1.1 validator wires in. + /// Pins the behaviour expressed by the test name: simple axis inside devices envelope is xsd valid. [Test] [Category("XsdLoadStrict")] public void Simple_Axis_inside_devices_envelope_is_xsd_valid() @@ -127,6 +132,7 @@ public void Simple_Axis_inside_devices_envelope_is_xsd_valid() "XSD validation produced errors:\n - " + string.Join("\n - ", errors)); } + /// Pins the behaviour expressed by the test name: axis data set inside devices envelope is xsd valid. [Test] [Category("XsdLoadStrict")] public void AxisDataSet_inside_devices_envelope_is_xsd_valid() @@ -152,6 +158,7 @@ public void AxisDataSet_inside_devices_envelope_is_xsd_valid() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: axis data set with illegal w key is dropped and does not corrupt xyz. [Test] public void AxisDataSet_with_illegal_W_key_is_dropped_and_does_not_corrupt_xyz() { @@ -171,6 +178,7 @@ public void AxisDataSet_with_illegal_W_key_is_dropped_and_does_not_corrupt_xyz() Assert.That(ds.Z, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: axis data set with w key inside devices envelope is xsd valid at n m t o k e n layer. [Test] [Category("XsdLoadStrict")] public void AxisDataSet_with_W_key_inside_devices_envelope_is_xsd_valid_at_NMTOKEN_layer() @@ -199,6 +207,7 @@ public void AxisDataSet_with_W_key_inside_devices_envelope_is_xsd_valid_at_NMTOK + string.Join("\n - ", errors)); } + /// Pins the behaviour expressed by the test name: empty axis yields empty string value. [Test] public void Empty_Axis_yields_empty_string_value() { @@ -210,6 +219,7 @@ public void Empty_Axis_yields_empty_string_value() Assert.That(axis.Value, Is.Null.Or.Empty); } + /// Pins the behaviour expressed by the test name: null axis property emits no axis element. [Test] public void Null_axis_property_emits_no_Axis_element() { @@ -227,6 +237,7 @@ public void Null_axis_property_emits_no_Axis_element() Assert.That(xml, Does.Not.Contain("Pins the behaviour expressed by the test name: both axis and axis data set present data set wins. [Test] public void Both_Axis_and_AxisDataSet_present_DataSet_wins() { @@ -247,6 +258,7 @@ public void Both_Axis_and_AxisDataSet_present_DataSet_wins() Assert.That(((IAxisDataSet)motion.Axis).X, Is.EqualTo(9.0)); } + /// Pins the behaviour expressed by the test name: both axis and axis data set present inside envelope fails xsd. [Test] [Category("XsdLoadStrict")] public void Both_Axis_and_AxisDataSet_present_inside_envelope_fails_xsd() @@ -267,6 +279,7 @@ public void Both_Axis_and_AxisDataSet_present_inside_envelope_fails_xsd() "XSD must reject both and in the same ."); } + /// Pins the behaviour expressed by the test name: null motion writes nothing. [Test] public void Null_motion_writes_nothing() { diff --git a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs index d42cc62d1..c9e47519e 100644 --- a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs +++ b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs @@ -30,6 +30,7 @@ public class ConfigurationPolymorphicOriginRoundTripTests { // ---------------- positive: Motion + simple Origin ---------------- + /// Pins the behaviour expressed by the test name: simple origin serialises to text element on motion. [Test] public void Simple_Origin_serialises_to_text_element_on_Motion() { @@ -47,6 +48,7 @@ public void Simple_Origin_serialises_to_text_element_on_Motion() Assert.That(xml, Does.Not.Contain("Pins the behaviour expressed by the test name: simple origin deserialises to i origin on motion. [Test] public void Simple_Origin_deserialises_to_IOrigin_on_Motion() { @@ -63,6 +65,7 @@ public void Simple_Origin_deserialises_to_IOrigin_on_Motion() // ---------------- positive: Motion + OriginDataSet ---------------- + /// Pins the behaviour expressed by the test name: origin data set serialises to keyed entries on motion. [Test] public void OriginDataSet_serialises_to_keyed_entries_on_Motion() { @@ -82,6 +85,7 @@ public void OriginDataSet_serialises_to_keyed_entries_on_Motion() Assert.That(xml, Does.Contain("3")); } + /// Pins the behaviour expressed by the test name: origin data set deserialises to i origin data set on motion. [Test] public void OriginDataSet_deserialises_to_IOriginDataSet_on_Motion() { @@ -104,6 +108,7 @@ public void OriginDataSet_deserialises_to_IOriginDataSet_on_Motion() // ---------------- positive: CoordinateSystem + simple Origin ---------------- + /// Pins the behaviour expressed by the test name: simple origin serialises to text element on coordinate system. [Test] public void Simple_Origin_serialises_to_text_element_on_CoordinateSystem() { @@ -120,6 +125,7 @@ public void Simple_Origin_serialises_to_text_element_on_CoordinateSystem() Assert.That(xml, Does.Not.Contain("Pins the behaviour expressed by the test name: simple origin deserialises to i origin on coordinate system. [Test] public void Simple_Origin_deserialises_to_IOrigin_on_CoordinateSystem() { @@ -135,6 +141,7 @@ public void Simple_Origin_deserialises_to_IOrigin_on_CoordinateSystem() // ---------------- positive: CoordinateSystem + OriginDataSet ---------------- + /// Pins the behaviour expressed by the test name: origin data set serialises to keyed entries on coordinate system. [Test] public void OriginDataSet_serialises_to_keyed_entries_on_CoordinateSystem() { @@ -151,6 +158,7 @@ public void OriginDataSet_serialises_to_keyed_entries_on_CoordinateSystem() Assert.That(xml, Does.Contain("100")); } + /// Pins the behaviour expressed by the test name: origin data set deserialises to i origin data set on coordinate system. [Test] public void OriginDataSet_deserialises_to_IOriginDataSet_on_CoordinateSystem() { @@ -173,6 +181,7 @@ public void OriginDataSet_deserialises_to_IOriginDataSet_on_CoordinateSystem() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: origin data set with illegal key drops value without corruption. [Test] public void OriginDataSet_with_illegal_key_drops_value_without_corruption() { @@ -189,6 +198,7 @@ public void OriginDataSet_with_illegal_key_drops_value_without_corruption() Assert.That(ds.Z, Is.Null); } + /// Pins the behaviour expressed by the test name: empty origin yields empty string value. [Test] public void Empty_Origin_yields_empty_string_value() { @@ -200,6 +210,7 @@ public void Empty_Origin_yields_empty_string_value() Assert.That(origin.Value, Is.Null.Or.Empty); } + /// Pins the behaviour expressed by the test name: null origin property emits no origin element on motion. [Test] public void Null_origin_property_emits_no_Origin_element_on_Motion() { @@ -217,6 +228,7 @@ public void Null_origin_property_emits_no_Origin_element_on_Motion() Assert.That(xml, Does.Not.Contain("Pins the behaviour expressed by the test name: null origin property emits no origin element on coordinate system. [Test] public void Null_origin_property_emits_no_Origin_element_on_CoordinateSystem() { @@ -233,6 +245,7 @@ public void Null_origin_property_emits_no_Origin_element_on_CoordinateSystem() Assert.That(xml, Does.Not.Contain("Pins the behaviour expressed by the test name: both origin and origin data set present data set wins. [Test] public void Both_Origin_and_OriginDataSet_present_DataSet_wins() { @@ -252,6 +265,7 @@ public void Both_Origin_and_OriginDataSet_present_DataSet_wins() Assert.That(((IOriginDataSet)cs.Origin).X, Is.EqualTo("9")); } + /// Pins the behaviour expressed by the test name: null coordinate system writes nothing. [Test] public void Null_coordinateSystem_writes_nothing() { @@ -259,6 +273,7 @@ public void Null_coordinateSystem_writes_nothing() Assert.That(xml, Is.Empty); } + /// Pins the behaviour expressed by the test name: origin data set writes nothing for null input. [Test] public void OriginDataSet_writes_nothing_for_null_input() { @@ -266,6 +281,7 @@ public void OriginDataSet_writes_nothing_for_null_input() Assert.That(xml, Is.Empty); } + /// Pins the behaviour expressed by the test name: origin writes nothing for null input. [Test] public void Origin_writes_nothing_for_null_input() { diff --git a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs index fa02e17e4..8028f3c0d 100644 --- a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs +++ b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs @@ -30,6 +30,7 @@ public class ConfigurationPolymorphicRotationRoundTripTests { // ---------------- positive: simple Rotation ---------------- + /// Pins the behaviour expressed by the test name: simple rotation serialises to text element. [Test] public void Simple_Rotation_serialises_to_text_element() { @@ -44,6 +45,7 @@ public void Simple_Rotation_serialises_to_text_element() Assert.That(xml, Does.Not.Contain("Pins the behaviour expressed by the test name: simple rotation deserialises to i rotation. [Test] public void Simple_Rotation_deserialises_to_IRotation() { @@ -60,6 +62,7 @@ public void Simple_Rotation_deserialises_to_IRotation() // ---------------- positive: RotationDataSet ---------------- + /// Pins the behaviour expressed by the test name: rotation data set serialises to keyed entries. [Test] public void RotationDataSet_serialises_to_keyed_entries() { @@ -76,6 +79,7 @@ public void RotationDataSet_serialises_to_keyed_entries() Assert.That(xml, Does.Contain("30")); } + /// Pins the behaviour expressed by the test name: rotation data set deserialises to i rotation data set. [Test] public void RotationDataSet_deserialises_to_IRotationDataSet() { @@ -98,6 +102,7 @@ public void RotationDataSet_deserialises_to_IRotationDataSet() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: rotation data set with x key drops value without corruption. [Test] public void RotationDataSet_with_X_key_drops_value_without_corruption() { @@ -116,6 +121,7 @@ public void RotationDataSet_with_X_key_drops_value_without_corruption() Assert.That(ds.C, Is.Null); } + /// Pins the behaviour expressed by the test name: empty rotation yields empty string value. [Test] public void Empty_Rotation_yields_empty_string_value() { @@ -127,6 +133,7 @@ public void Empty_Rotation_yields_empty_string_value() Assert.That(r.Value, Is.Null.Or.Empty); } + /// Pins the behaviour expressed by the test name: null rotation property emits no rotation element. [Test] public void Null_rotation_property_emits_no_Rotation_element() { @@ -143,6 +150,7 @@ public void Null_rotation_property_emits_no_Rotation_element() Assert.That(xml, Does.Contain("1 2 3")); } + /// Pins the behaviour expressed by the test name: both rotation and rotation data set present data set wins. [Test] public void Both_Rotation_and_RotationDataSet_present_DataSet_wins() { @@ -161,6 +169,7 @@ public void Both_Rotation_and_RotationDataSet_present_DataSet_wins() Assert.That(((IRotationDataSet)t.Rotation).A, Is.EqualTo("9")); } + /// Pins the behaviour expressed by the test name: null transformation writes nothing. [Test] public void Null_transformation_writes_nothing() { @@ -168,6 +177,7 @@ public void Null_transformation_writes_nothing() Assert.That(xml, Is.Empty); } + /// Pins the behaviour expressed by the test name: rotation writes nothing for null input. [Test] public void Rotation_writes_nothing_for_null_input() { @@ -175,6 +185,7 @@ public void Rotation_writes_nothing_for_null_input() Assert.That(xml, Is.Empty); } + /// Pins the behaviour expressed by the test name: rotation data set writes nothing for null input. [Test] public void RotationDataSet_writes_nothing_for_null_input() { @@ -182,6 +193,7 @@ public void RotationDataSet_writes_nothing_for_null_input() Assert.That(xml, Is.Empty); } + /// Pins the behaviour expressed by the test name: rotation data set skips null or empty values on write. [Test] public void RotationDataSet_skips_null_or_empty_values_on_write() { diff --git a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs index 65046bf22..3a9b2676d 100644 --- a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs +++ b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs @@ -28,6 +28,7 @@ public class ConfigurationPolymorphicScaleRoundTripTests { // ---------------- positive: simple Scale ---------------- + /// Pins the behaviour expressed by the test name: simple scale serialises to text element. [Test] public void Simple_Scale_serialises_to_text_element() { @@ -44,6 +45,7 @@ public void Simple_Scale_serialises_to_text_element() Assert.That(xml, Does.Not.Contain("Pins the behaviour expressed by the test name: simple scale deserialises to i scale. [Test] public void Simple_Scale_deserialises_to_IScale() { @@ -60,6 +62,7 @@ public void Simple_Scale_deserialises_to_IScale() // ---------------- positive: ScaleDataSet ---------------- + /// Pins the behaviour expressed by the test name: scale data set serialises to keyed entries. [Test] public void ScaleDataSet_serialises_to_keyed_entries() { @@ -78,6 +81,7 @@ public void ScaleDataSet_serialises_to_keyed_entries() Assert.That(xml, Does.Contain("3.5")); } + /// Pins the behaviour expressed by the test name: scale data set deserialises to i scale data set. [Test] public void ScaleDataSet_deserialises_to_IScaleDataSet() { @@ -100,6 +104,7 @@ public void ScaleDataSet_deserialises_to_IScaleDataSet() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: scale data set with illegal key drops value without corruption. [Test] public void ScaleDataSet_with_illegal_key_drops_value_without_corruption() { @@ -116,6 +121,7 @@ public void ScaleDataSet_with_illegal_key_drops_value_without_corruption() Assert.That(ds.Z, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: scale data set with unparseable value falls back to zero. [Test] public void ScaleDataSet_with_unparseable_value_falls_back_to_zero() { @@ -129,6 +135,7 @@ public void ScaleDataSet_with_unparseable_value_falls_back_to_zero() Assert.That(ds.X, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: scale data set with empty value text falls back to zero. [Test] public void ScaleDataSet_with_empty_value_text_falls_back_to_zero() { @@ -142,6 +149,7 @@ public void ScaleDataSet_with_empty_value_text_falls_back_to_zero() Assert.That(ds.X, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: empty scale yields empty string value. [Test] public void Empty_Scale_yields_empty_string_value() { @@ -153,6 +161,7 @@ public void Empty_Scale_yields_empty_string_value() Assert.That(s.Value, Is.Null.Or.Empty); } + /// Pins the behaviour expressed by the test name: null scale property emits no scale element. [Test] public void Null_scale_property_emits_no_Scale_element() { @@ -169,6 +178,7 @@ public void Null_scale_property_emits_no_Scale_element() Assert.That(xml, Does.Not.Contain("Pins the behaviour expressed by the test name: both scale and scale data set present data set wins. [Test] public void Both_Scale_and_ScaleDataSet_present_DataSet_wins() { @@ -185,6 +195,7 @@ public void Both_Scale_and_ScaleDataSet_present_DataSet_wins() Assert.That(((IScaleDataSet)sm.Scale).X, Is.EqualTo(9.0)); } + /// Pins the behaviour expressed by the test name: null solid model writes nothing. [Test] public void Null_solidModel_writes_nothing() { @@ -192,6 +203,7 @@ public void Null_solidModel_writes_nothing() Assert.That(xml, Is.Empty); } + /// Pins the behaviour expressed by the test name: scale writes nothing for null input. [Test] public void Scale_writes_nothing_for_null_input() { @@ -199,6 +211,7 @@ public void Scale_writes_nothing_for_null_input() Assert.That(xml, Is.Empty); } + /// Pins the behaviour expressed by the test name: scale data set writes nothing for null input. [Test] public void ScaleDataSet_writes_nothing_for_null_input() { @@ -206,6 +219,7 @@ public void ScaleDataSet_writes_nothing_for_null_input() Assert.That(xml, Is.Empty); } + /// Pins the behaviour expressed by the test name: scale data set with null entries list yields zero components. [Test] public void ScaleDataSet_with_null_entries_list_yields_zero_components() { diff --git a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs index cc246aa35..a133aea9f 100644 --- a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs +++ b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs @@ -29,6 +29,7 @@ public class ConfigurationPolymorphicTranslationRoundTripTests { // ---------------- positive: simple Translation ---------------- + /// Pins the behaviour expressed by the test name: simple translation serialises to text element. [Test] public void Simple_Translation_serialises_to_text_element() { @@ -43,6 +44,7 @@ public void Simple_Translation_serialises_to_text_element() Assert.That(xml, Does.Not.Contain("Pins the behaviour expressed by the test name: simple translation deserialises to i translation. [Test] public void Simple_Translation_deserialises_to_ITranslation() { @@ -59,6 +61,7 @@ public void Simple_Translation_deserialises_to_ITranslation() // ---------------- positive: TranslationDataSet ---------------- + /// Pins the behaviour expressed by the test name: translation data set serialises to keyed entries. [Test] public void TranslationDataSet_serialises_to_keyed_entries() { @@ -75,6 +78,7 @@ public void TranslationDataSet_serialises_to_keyed_entries() Assert.That(xml, Does.Contain("3")); } + /// Pins the behaviour expressed by the test name: translation data set deserialises to i translation data set. [Test] public void TranslationDataSet_deserialises_to_ITranslationDataSet() { @@ -97,6 +101,7 @@ public void TranslationDataSet_deserialises_to_ITranslationDataSet() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: translation data set with illegal key drops value without corruption. [Test] public void TranslationDataSet_with_illegal_key_drops_value_without_corruption() { @@ -113,6 +118,7 @@ public void TranslationDataSet_with_illegal_key_drops_value_without_corruption() Assert.That(ds.Z, Is.Null); } + /// Pins the behaviour expressed by the test name: empty translation yields empty string value. [Test] public void Empty_Translation_yields_empty_string_value() { @@ -124,6 +130,7 @@ public void Empty_Translation_yields_empty_string_value() Assert.That(t.Value, Is.Null.Or.Empty); } + /// Pins the behaviour expressed by the test name: null translation property emits no translation element. [Test] public void Null_translation_property_emits_no_Translation_element() { @@ -140,6 +147,7 @@ public void Null_translation_property_emits_no_Translation_element() Assert.That(xml, Does.Contain("1 2 3")); } + /// Pins the behaviour expressed by the test name: both translation and translation data set present data set wins. [Test] public void Both_Translation_and_TranslationDataSet_present_DataSet_wins() { @@ -156,6 +164,7 @@ public void Both_Translation_and_TranslationDataSet_present_DataSet_wins() Assert.That(((ITranslationDataSet)t.Translation).X, Is.EqualTo("9")); } + /// Pins the behaviour expressed by the test name: translation writes nothing for null input. [Test] public void Translation_writes_nothing_for_null_input() { @@ -163,6 +172,7 @@ public void Translation_writes_nothing_for_null_input() Assert.That(xml, Is.Empty); } + /// Pins the behaviour expressed by the test name: translation data set writes nothing for null input. [Test] public void TranslationDataSet_writes_nothing_for_null_input() { @@ -170,6 +180,7 @@ public void TranslationDataSet_writes_nothing_for_null_input() Assert.That(xml, Is.Empty); } + /// Pins the behaviour expressed by the test name: translation data set skips null entries on write. [Test] public void TranslationDataSet_skips_null_entries_on_write() { @@ -182,6 +193,7 @@ public void TranslationDataSet_skips_null_entries_on_write() Assert.That(xml, Does.Not.Contain("key=\"Z\"")); } + /// Pins the behaviour expressed by the test name: transformation round trip preserves both translation and rotation. [Test] public void Transformation_round_trip_preserves_both_Translation_and_Rotation() { diff --git a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/CoordinateSystemDescriptionWriteTests.cs b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/CoordinateSystemDescriptionWriteTests.cs index 1dd612476..8ef57edde 100644 --- a/tests/MTConnect.NET-XML-Tests/Devices/Configurations/CoordinateSystemDescriptionWriteTests.cs +++ b/tests/MTConnect.NET-XML-Tests/Devices/Configurations/CoordinateSystemDescriptionWriteTests.cs @@ -37,6 +37,7 @@ public class CoordinateSystemDescriptionWriteTests { // ---------------- Description child element ---------------- + /// Pins the behaviour expressed by the test name: non empty description emits description element. [Test] public void NonEmpty_Description_emits_Description_element() { @@ -52,6 +53,7 @@ public void NonEmpty_Description_emits_Description_element() Assert.That(xml, Does.Contain("primary machine frame")); } + /// Pins the behaviour expressed by the test name: null description emits no description element. [Test] public void Null_Description_emits_no_Description_element() { @@ -67,6 +69,7 @@ public void Null_Description_emits_no_Description_element() Assert.That(xml, Does.Not.Contain("Pins the behaviour expressed by the test name: empty description emits no description element. [Test] public void Empty_Description_emits_no_Description_element() { @@ -84,6 +87,7 @@ public void Empty_Description_emits_no_Description_element() // ---------------- Optional name / nativeName / parentIdRef attributes ---------------- + /// Pins the behaviour expressed by the test name: optional attributes emit when set. [Test] public void Optional_attributes_emit_when_set() { @@ -107,6 +111,7 @@ public void Optional_attributes_emit_when_set() // ---------------- Transformation child element ---------------- + /// Pins the behaviour expressed by the test name: non null transformation emits transformation element on write. [Test] public void NonNull_Transformation_emits_Transformation_element_on_write() { @@ -126,6 +131,7 @@ public void NonNull_Transformation_emits_Transformation_element_on_write() Assert.That(xml, Does.Contain("1 2 3")); } + /// Pins the behaviour expressed by the test name: transformation round trips through to coordinate system. [Test] public void Transformation_round_trips_through_ToCoordinateSystem() { diff --git a/tests/MTConnect.NET-XML-Tests/Devices/DeviceCtorDefaultsWireShapeTests.cs b/tests/MTConnect.NET-XML-Tests/Devices/DeviceCtorDefaultsWireShapeTests.cs index e185e4770..11608f028 100644 --- a/tests/MTConnect.NET-XML-Tests/Devices/DeviceCtorDefaultsWireShapeTests.cs +++ b/tests/MTConnect.NET-XML-Tests/Devices/DeviceCtorDefaultsWireShapeTests.cs @@ -24,6 +24,7 @@ namespace MTConnect.Tests.XML.Devices [TestFixture] public class DeviceCtorDefaultsWireShapeTests { + /// Pins the behaviour expressed by the test name: default constructed device emits empty identity attributes. [Test] public void Default_constructed_Device_emits_empty_identity_attributes() { @@ -40,6 +41,7 @@ public void Default_constructed_Device_emits_empty_identity_attributes() "Default ctor must not emit the placeholder name 'dev'."); } + /// Pins the behaviour expressed by the test name: caller set identity round trips through x m l. [Test] public void Caller_set_identity_round_trips_through_XML() { @@ -57,6 +59,7 @@ public void Caller_set_identity_round_trips_through_XML() Assert.That(xml, Does.Contain("uuid=\"uuid-A\"")); } + /// Pins the behaviour expressed by the test name: sequential default devices emit identical empty uuid attributes. [Test] public void Sequential_default_Devices_emit_identical_empty_uuid_attributes() { diff --git a/tests/MTConnect.NET-XML-Tests/Devices/DeviceLoad.cs b/tests/MTConnect.NET-XML-Tests/Devices/DeviceLoad.cs index 99baaf1fe..6177e7a43 100644 --- a/tests/MTConnect.NET-XML-Tests/Devices/DeviceLoad.cs +++ b/tests/MTConnect.NET-XML-Tests/Devices/DeviceLoad.cs @@ -5,15 +5,18 @@ namespace MTConnect.Tests.XML.Devices { + /// Represents the device files. public class DeviceFiles { private const string DevicesDirectory = "Device-Files"; private const string DevicesFilename = "devices-okuma-lathe.xml"; + /// Sets up the fixture before each test. [SetUp] public void Setup() { } + /// Pins the behaviour expressed by the test name: load file. [Test] public void LoadFile() { @@ -37,6 +40,7 @@ public void LoadFile() } } + /// Pins the behaviour expressed by the test name: load files. [Test] public void LoadFiles() { diff --git a/tests/MTConnect.NET-XML-Tests/Devices/XmlDataItemEmptyNameOmissionTests.cs b/tests/MTConnect.NET-XML-Tests/Devices/XmlDataItemEmptyNameOmissionTests.cs index ceaedaf95..6fafb868c 100644 --- a/tests/MTConnect.NET-XML-Tests/Devices/XmlDataItemEmptyNameOmissionTests.cs +++ b/tests/MTConnect.NET-XML-Tests/Devices/XmlDataItemEmptyNameOmissionTests.cs @@ -27,6 +27,7 @@ namespace MTConnect.Tests.XML.Devices [TestFixture] public class XmlDataItemEmptyNameOmissionTests { + /// Pins the behaviour expressed by the test name: xml formatter omits name attribute when source name is null. [Test] public void Xml_formatter_omits_name_attribute_when_source_Name_is_null() { @@ -44,6 +45,7 @@ public void Xml_formatter_omits_name_attribute_when_source_Name_is_null() "XmlDataItem must omit the 'name' attribute when source Name is null."); } + /// Pins the behaviour expressed by the test name: xml formatter omits name attribute when source name is empty. [Test] public void Xml_formatter_omits_name_attribute_when_source_Name_is_empty() { @@ -61,6 +63,7 @@ public void Xml_formatter_omits_name_attribute_when_source_Name_is_empty() "XmlDataItem must omit the 'name' attribute when source Name is empty."); } + /// Pins the behaviour expressed by the test name: xml formatter emits name attribute when source name is set. [Test] public void Xml_formatter_emits_name_attribute_when_source_Name_is_set() { diff --git a/tests/MTConnect.NET-XML-Tests/Headers/HeaderVersionXmlRoundTripTests.cs b/tests/MTConnect.NET-XML-Tests/Headers/HeaderVersionXmlRoundTripTests.cs index 683fc8256..a6e2dd303 100644 --- a/tests/MTConnect.NET-XML-Tests/Headers/HeaderVersionXmlRoundTripTests.cs +++ b/tests/MTConnect.NET-XML-Tests/Headers/HeaderVersionXmlRoundTripTests.cs @@ -28,6 +28,7 @@ namespace MTConnect.Tests.Xml.Headers { + /// Pins the behaviour expressed by the test name: header version xml round trip tests. [TestFixture] public class HeaderVersionXmlRoundTripTests { @@ -42,6 +43,8 @@ public class HeaderVersionXmlRoundTripTests // library cannot serialize. Versions added beyond this set // require matching entries in Namespaces.cs and Schemas.cs // before the test case can be added here. + /// Runs the all supported versions operation. + /// The result of the operation. public static System.Collections.Generic.IEnumerable AllSupportedVersions() { return new[] @@ -73,6 +76,8 @@ private static string ExpectedHeaderVersion(Version configuredVersion) 0).ToString(); } + /// Pins the behaviour expressed by the test name: devices xml payload carries configured mtconnect release in header version. + /// The configured version. [TestCaseSource(nameof(AllSupportedVersions))] public void Devices_xml_payload_carries_configured_mtconnect_release_in_header_version(Version configuredVersion) { diff --git a/tests/MTConnect.NET-XML-Tests/Streams/Current.cs b/tests/MTConnect.NET-XML-Tests/Streams/Current.cs index 0b9f46c2b..e8cb9efa1 100644 --- a/tests/MTConnect.NET-XML-Tests/Streams/Current.cs +++ b/tests/MTConnect.NET-XML-Tests/Streams/Current.cs @@ -9,8 +9,10 @@ namespace MTConnect.Tests.XML.Streams { + /// Represents the current. public class Current { + /// Pins the behaviour expressed by the test name: read stream test files. [Test] public void ReadStreamTestFiles() { diff --git a/tests/MTConnect.NET-XML-Tests/XmlStreamsResponseDocumentTests.cs b/tests/MTConnect.NET-XML-Tests/XmlStreamsResponseDocumentTests.cs index 7ffac945e..032f3aa26 100644 --- a/tests/MTConnect.NET-XML-Tests/XmlStreamsResponseDocumentTests.cs +++ b/tests/MTConnect.NET-XML-Tests/XmlStreamsResponseDocumentTests.cs @@ -10,8 +10,10 @@ namespace MTConnect.Tests.XML { + /// Represents the xml streams response document tests. public sealed class XmlStreamsResponseDocumentTests { + /// Pins the behaviour expressed by the test name: two conditions should be parsed. [Test] public void TwoConditionsShouldBeParsed() { From d21463a527029b07756b989cdbf85db154138c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:30:06 +0200 Subject: [PATCH 11/29] docs(json-tests): author XML doc comments on test surface --- .../ConfigurationPolymorphicAxisRoundTripTests.cs | 12 ++++++++++++ .../ConfigurationPolymorphicOriginRoundTripTests.cs | 12 ++++++++++++ ...ConfigurationPolymorphicRotationRoundTripTests.cs | 11 +++++++++++ .../ConfigurationPolymorphicScaleRoundTripTests.cs | 11 +++++++++++ ...figurationPolymorphicTranslationRoundTripTests.cs | 10 ++++++++++ .../Devices/JsonDataItemEmptyNameOmissionTests.cs | 4 ++++ .../Devices/JsonDataItemNameAttributePinTests.cs | 2 ++ tests/MTConnect.NET-JSON-Tests/SanityTests.cs | 2 ++ 8 files changed, 64 insertions(+) diff --git a/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs b/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs index 6ddc567c0..54c21d832 100644 --- a/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs +++ b/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicAxisRoundTripTests.cs @@ -27,6 +27,7 @@ public class ConfigurationPolymorphicAxisRoundTripTests { // ---------------- positive: simple Axis ---------------- + /// Pins the behaviour expressed by the test name: simple axis serialises to value field. [Test] public void Simple_Axis_serialises_to_value_field() { @@ -44,6 +45,7 @@ public void Simple_Axis_serialises_to_value_field() Assert.That(json, Does.Not.Contain("axisDataSet")); } + /// Pins the behaviour expressed by the test name: simple axis deserialises to i axis. [Test] public void Simple_Axis_deserialises_to_IAxis() { @@ -60,6 +62,7 @@ public void Simple_Axis_deserialises_to_IAxis() // ---------------- positive: AxisDataSet ---------------- + /// Pins the behaviour expressed by the test name: axis data set serialises to xyz flat object. [Test] public void AxisDataSet_serialises_to_xyz_flat_object() { @@ -77,6 +80,7 @@ public void AxisDataSet_serialises_to_xyz_flat_object() Assert.That(json, Does.Not.Contain("\"axis\":{")); } + /// Pins the behaviour expressed by the test name: axis data set deserialises to i axis data set. [Test] public void AxisDataSet_deserialises_to_IAxisDataSet() { @@ -95,6 +99,7 @@ public void AxisDataSet_deserialises_to_IAxisDataSet() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: null axis property emits no axis field. [Test] public void Null_axis_property_emits_no_axis_field() { @@ -112,6 +117,7 @@ public void Null_axis_property_emits_no_axis_field() Assert.That(json, Does.Not.Contain("axisDataSet")); } + /// Pins the behaviour expressed by the test name: both axis and axis data set present data set wins. [Test] public void Both_axis_and_axisDataSet_present_DataSet_wins() { @@ -128,6 +134,7 @@ public void Both_axis_and_axisDataSet_present_DataSet_wins() Assert.That(((IAxisDataSet)motion.Axis).X, Is.EqualTo(9.0)); } + /// Pins the behaviour expressed by the test name: default json axis constructor yields null value. [Test] public void Default_JsonAxis_constructor_yields_null_value() { @@ -138,6 +145,7 @@ public void Default_JsonAxis_constructor_yields_null_value() Assert.That(ax.Value, Is.Null); } + /// Pins the behaviour expressed by the test name: default json axis data set constructor yields zero components. [Test] public void Default_JsonAxisDataSet_constructor_yields_zero_components() { @@ -149,6 +157,7 @@ public void Default_JsonAxisDataSet_constructor_yields_zero_components() Assert.That(ds.Z, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: json axis ctor with null input keeps default values. [Test] public void JsonAxis_ctor_with_null_input_keeps_default_values() { @@ -157,6 +166,7 @@ public void JsonAxis_ctor_with_null_input_keeps_default_values() Assert.That(ja.Value, Is.Null); } + /// Pins the behaviour expressed by the test name: json axis data set ctor with null input keeps default values. [Test] public void JsonAxisDataSet_ctor_with_null_input_keeps_default_values() { @@ -165,6 +175,7 @@ public void JsonAxisDataSet_ctor_with_null_input_keeps_default_values() Assert.That(ja.X, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: round trip preserves axis data set components. [Test] public void Round_trip_preserves_AxisDataSet_components() { @@ -187,6 +198,7 @@ public void Round_trip_preserves_AxisDataSet_components() Assert.That(ds.Z, Is.EqualTo(3.5)); } + /// Pins the behaviour expressed by the test name: null motion passed to json motion ctor keeps default values. [Test] public void Null_motion_passed_to_JsonMotion_ctor_keeps_default_values() { diff --git a/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs b/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs index 74238c420..b636805fe 100644 --- a/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs +++ b/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicOriginRoundTripTests.cs @@ -28,6 +28,7 @@ public class ConfigurationPolymorphicOriginRoundTripTests { // ---------------- positive: Motion + simple Origin ---------------- + /// Pins the behaviour expressed by the test name: simple origin serialises to value field on motion. [Test] public void Simple_Origin_serialises_to_value_field_on_Motion() { @@ -45,6 +46,7 @@ public void Simple_Origin_serialises_to_value_field_on_Motion() Assert.That(json, Does.Not.Contain("originDataSet")); } + /// Pins the behaviour expressed by the test name: simple origin deserialises to i origin on motion. [Test] public void Simple_Origin_deserialises_to_IOrigin_on_Motion() { @@ -60,6 +62,7 @@ public void Simple_Origin_deserialises_to_IOrigin_on_Motion() // ---------------- positive: Motion + OriginDataSet ---------------- + /// Pins the behaviour expressed by the test name: origin data set serialises to xyz object on motion. [Test] public void OriginDataSet_serialises_to_xyz_object_on_Motion() { @@ -76,6 +79,7 @@ public void OriginDataSet_serialises_to_xyz_object_on_Motion() Assert.That(json, Does.Contain("\"originDataSet\":{\"x\":\"1\",\"y\":\"2\",\"z\":\"3\"}")); } + /// Pins the behaviour expressed by the test name: origin data set deserialises to i origin data set on motion. [Test] public void OriginDataSet_deserialises_to_IOriginDataSet_on_Motion() { @@ -94,6 +98,7 @@ public void OriginDataSet_deserialises_to_IOriginDataSet_on_Motion() // ---------------- positive: CoordinateSystem ---------------- + /// Pins the behaviour expressed by the test name: simple origin round trips on coordinate system. [Test] public void Simple_Origin_round_trips_on_CoordinateSystem() { @@ -113,6 +118,7 @@ public void Simple_Origin_round_trips_on_CoordinateSystem() Assert.That(((IOrigin)output.Origin).Value, Is.EqualTo("10 20 30")); } + /// Pins the behaviour expressed by the test name: origin data set round trips on coordinate system. [Test] public void OriginDataSet_round_trips_on_CoordinateSystem() { @@ -133,6 +139,7 @@ public void OriginDataSet_round_trips_on_CoordinateSystem() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: both origin and origin data set present data set wins on motion. [Test] public void Both_origin_and_originDataSet_present_DataSet_wins_on_Motion() { @@ -147,6 +154,7 @@ public void Both_origin_and_originDataSet_present_DataSet_wins_on_Motion() Assert.That(((IOriginDataSet)motion.Origin).X, Is.EqualTo("9")); } + /// Pins the behaviour expressed by the test name: json origin default constructor yields null value. [Test] public void JsonOrigin_default_constructor_yields_null_value() { @@ -157,6 +165,7 @@ public void JsonOrigin_default_constructor_yields_null_value() Assert.That(origin.Value, Is.Null); } + /// Pins the behaviour expressed by the test name: json origin data set default constructor yields null components. [Test] public void JsonOriginDataSet_default_constructor_yields_null_components() { @@ -168,6 +177,7 @@ public void JsonOriginDataSet_default_constructor_yields_null_components() Assert.That(ds.Z, Is.Null); } + /// Pins the behaviour expressed by the test name: json origin ctor with null input keeps default values. [Test] public void JsonOrigin_ctor_with_null_input_keeps_default_values() { @@ -175,6 +185,7 @@ public void JsonOrigin_ctor_with_null_input_keeps_default_values() Assert.That(jo.Value, Is.Null); } + /// Pins the behaviour expressed by the test name: json origin data set ctor with null input keeps default values. [Test] public void JsonOriginDataSet_ctor_with_null_input_keeps_default_values() { @@ -182,6 +193,7 @@ public void JsonOriginDataSet_ctor_with_null_input_keeps_default_values() Assert.That(jo.X, Is.Null); } + /// Pins the behaviour expressed by the test name: null coordinate system passed to ctor keeps default values. [Test] public void Null_coordinateSystem_passed_to_ctor_keeps_default_values() { diff --git a/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs b/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs index f9fb3d60e..0f446a100 100644 --- a/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs +++ b/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicRotationRoundTripTests.cs @@ -28,6 +28,7 @@ public class ConfigurationPolymorphicRotationRoundTripTests { // ---------------- positive: simple Rotation ---------------- + /// Pins the behaviour expressed by the test name: simple rotation serialises to value field. [Test] public void Simple_Rotation_serialises_to_value_field() { @@ -42,6 +43,7 @@ public void Simple_Rotation_serialises_to_value_field() Assert.That(json, Does.Not.Contain("rotationDataSet")); } + /// Pins the behaviour expressed by the test name: simple rotation deserialises to i rotation. [Test] public void Simple_Rotation_deserialises_to_IRotation() { @@ -56,6 +58,7 @@ public void Simple_Rotation_deserialises_to_IRotation() // ---------------- positive: RotationDataSet ---------------- + /// Pins the behaviour expressed by the test name: rotation data set serialises to abc object. [Test] public void RotationDataSet_serialises_to_abc_object() { @@ -69,6 +72,7 @@ public void RotationDataSet_serialises_to_abc_object() Assert.That(json, Does.Contain("\"rotationDataSet\":{\"a\":\"10\",\"b\":\"20\",\"c\":\"30\"}")); } + /// Pins the behaviour expressed by the test name: rotation data set deserialises to i rotation data set. [Test] public void RotationDataSet_deserialises_to_IRotationDataSet() { @@ -86,6 +90,7 @@ public void RotationDataSet_deserialises_to_IRotationDataSet() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: both rotation and rotation data set present data set wins. [Test] public void Both_rotation_and_rotationDataSet_present_DataSet_wins() { @@ -99,6 +104,7 @@ public void Both_rotation_and_rotationDataSet_present_DataSet_wins() Assert.That(((IRotationDataSet)t.Rotation).A, Is.EqualTo("9")); } + /// Pins the behaviour expressed by the test name: json rotation default constructor yields null value. [Test] public void JsonRotation_default_constructor_yields_null_value() { @@ -109,6 +115,7 @@ public void JsonRotation_default_constructor_yields_null_value() Assert.That(r.Value, Is.Null); } + /// Pins the behaviour expressed by the test name: json rotation data set default constructor yields null components. [Test] public void JsonRotationDataSet_default_constructor_yields_null_components() { @@ -120,6 +127,7 @@ public void JsonRotationDataSet_default_constructor_yields_null_components() Assert.That(ds.C, Is.Null); } + /// Pins the behaviour expressed by the test name: json rotation ctor with null input keeps default values. [Test] public void JsonRotation_ctor_with_null_input_keeps_default_values() { @@ -127,6 +135,7 @@ public void JsonRotation_ctor_with_null_input_keeps_default_values() Assert.That(jr.Value, Is.Null); } + /// Pins the behaviour expressed by the test name: json rotation data set ctor with null input keeps default values. [Test] public void JsonRotationDataSet_ctor_with_null_input_keeps_default_values() { @@ -134,6 +143,7 @@ public void JsonRotationDataSet_ctor_with_null_input_keeps_default_values() Assert.That(jr.A, Is.Null); } + /// Pins the behaviour expressed by the test name: null transformation passed to ctor keeps default values. [Test] public void Null_transformation_passed_to_ctor_keeps_default_values() { @@ -142,6 +152,7 @@ public void Null_transformation_passed_to_ctor_keeps_default_values() Assert.That(jt.RotationDataSet, Is.Null); } + /// Pins the behaviour expressed by the test name: null rotation property emits no rotation field. [Test] public void Null_rotation_property_emits_no_rotation_field() { diff --git a/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs b/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs index 12106db6e..525be7532 100644 --- a/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs +++ b/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicScaleRoundTripTests.cs @@ -26,6 +26,7 @@ public class ConfigurationPolymorphicScaleRoundTripTests { // ---------------- positive: simple Scale ---------------- + /// Pins the behaviour expressed by the test name: simple scale serialises to value field. [Test] public void Simple_Scale_serialises_to_value_field() { @@ -42,6 +43,7 @@ public void Simple_Scale_serialises_to_value_field() Assert.That(json, Does.Not.Contain("scaleDataSet")); } + /// Pins the behaviour expressed by the test name: simple scale deserialises to i scale. [Test] public void Simple_Scale_deserialises_to_IScale() { @@ -57,6 +59,7 @@ public void Simple_Scale_deserialises_to_IScale() // ---------------- positive: ScaleDataSet ---------------- + /// Pins the behaviour expressed by the test name: scale data set serialises to xyz object. [Test] public void ScaleDataSet_serialises_to_xyz_object() { @@ -72,6 +75,7 @@ public void ScaleDataSet_serialises_to_xyz_object() Assert.That(json, Does.Contain("\"scaleDataSet\":{\"x\":1.5,\"y\":2.5,\"z\":3.5}")); } + /// Pins the behaviour expressed by the test name: scale data set deserialises to i scale data set. [Test] public void ScaleDataSet_deserialises_to_IScaleDataSet() { @@ -90,6 +94,7 @@ public void ScaleDataSet_deserialises_to_IScaleDataSet() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: both scale and scale data set present data set wins. [Test] public void Both_scale_and_scaleDataSet_present_DataSet_wins() { @@ -104,6 +109,7 @@ public void Both_scale_and_scaleDataSet_present_DataSet_wins() Assert.That(((IScaleDataSet)sm.Scale).X, Is.EqualTo(9.0)); } + /// Pins the behaviour expressed by the test name: null scale property emits no scale field. [Test] public void Null_scale_property_emits_no_scale_field() { @@ -120,6 +126,7 @@ public void Null_scale_property_emits_no_scale_field() Assert.That(json, Does.Not.Contain("scaleDataSet")); } + /// Pins the behaviour expressed by the test name: json scale default constructor yields null value. [Test] public void JsonScale_default_constructor_yields_null_value() { @@ -130,6 +137,7 @@ public void JsonScale_default_constructor_yields_null_value() Assert.That(s.Value, Is.Null); } + /// Pins the behaviour expressed by the test name: json scale data set default constructor yields zero components. [Test] public void JsonScaleDataSet_default_constructor_yields_zero_components() { @@ -139,6 +147,7 @@ public void JsonScaleDataSet_default_constructor_yields_zero_components() Assert.That(ds.X, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: json scale ctor with null input keeps default values. [Test] public void JsonScale_ctor_with_null_input_keeps_default_values() { @@ -146,6 +155,7 @@ public void JsonScale_ctor_with_null_input_keeps_default_values() Assert.That(js.Value, Is.Null); } + /// Pins the behaviour expressed by the test name: json scale data set ctor with null input keeps default values. [Test] public void JsonScaleDataSet_ctor_with_null_input_keeps_default_values() { @@ -153,6 +163,7 @@ public void JsonScaleDataSet_ctor_with_null_input_keeps_default_values() Assert.That(js.X, Is.EqualTo(0.0)); } + /// Pins the behaviour expressed by the test name: null solid model passed to ctor keeps default values. [Test] public void Null_solidModel_passed_to_ctor_keeps_default_values() { diff --git a/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs b/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs index 32a5b2d6c..b404c3619 100644 --- a/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs +++ b/tests/MTConnect.NET-JSON-Tests/Devices/Configurations/ConfigurationPolymorphicTranslationRoundTripTests.cs @@ -28,6 +28,7 @@ public class ConfigurationPolymorphicTranslationRoundTripTests { // ---------------- positive: simple Translation ---------------- + /// Pins the behaviour expressed by the test name: simple translation serialises to value field. [Test] public void Simple_Translation_serialises_to_value_field() { @@ -42,6 +43,7 @@ public void Simple_Translation_serialises_to_value_field() Assert.That(json, Does.Not.Contain("translationDataSet")); } + /// Pins the behaviour expressed by the test name: simple translation deserialises to i translation. [Test] public void Simple_Translation_deserialises_to_ITranslation() { @@ -56,6 +58,7 @@ public void Simple_Translation_deserialises_to_ITranslation() // ---------------- positive: TranslationDataSet ---------------- + /// Pins the behaviour expressed by the test name: translation data set serialises to xyz object. [Test] public void TranslationDataSet_serialises_to_xyz_object() { @@ -69,6 +72,7 @@ public void TranslationDataSet_serialises_to_xyz_object() Assert.That(json, Does.Contain("\"translationDataSet\":{\"x\":\"1\",\"y\":\"2\",\"z\":\"3\"}")); } + /// Pins the behaviour expressed by the test name: translation data set deserialises to i translation data set. [Test] public void TranslationDataSet_deserialises_to_ITranslationDataSet() { @@ -86,6 +90,7 @@ public void TranslationDataSet_deserialises_to_ITranslationDataSet() // ---------------- negative ---------------- + /// Pins the behaviour expressed by the test name: both translation and translation data set present data set wins. [Test] public void Both_translation_and_translationDataSet_present_DataSet_wins() { @@ -99,6 +104,7 @@ public void Both_translation_and_translationDataSet_present_DataSet_wins() Assert.That(((ITranslationDataSet)t.Translation).X, Is.EqualTo("9")); } + /// Pins the behaviour expressed by the test name: json translation default constructor yields null value. [Test] public void JsonTranslation_default_constructor_yields_null_value() { @@ -109,6 +115,7 @@ public void JsonTranslation_default_constructor_yields_null_value() Assert.That(t.Value, Is.Null); } + /// Pins the behaviour expressed by the test name: json translation data set default constructor yields null components. [Test] public void JsonTranslationDataSet_default_constructor_yields_null_components() { @@ -120,6 +127,7 @@ public void JsonTranslationDataSet_default_constructor_yields_null_components() Assert.That(ds.Z, Is.Null); } + /// Pins the behaviour expressed by the test name: json translation ctor with null input keeps default values. [Test] public void JsonTranslation_ctor_with_null_input_keeps_default_values() { @@ -127,6 +135,7 @@ public void JsonTranslation_ctor_with_null_input_keeps_default_values() Assert.That(jt.Value, Is.Null); } + /// Pins the behaviour expressed by the test name: json translation data set ctor with null input keeps default values. [Test] public void JsonTranslationDataSet_ctor_with_null_input_keeps_default_values() { @@ -134,6 +143,7 @@ public void JsonTranslationDataSet_ctor_with_null_input_keeps_default_values() Assert.That(jt.X, Is.Null); } + /// Pins the behaviour expressed by the test name: both translation and rotation data set round trip independently. [Test] public void Both_Translation_and_Rotation_DataSet_round_trip_independently() { diff --git a/tests/MTConnect.NET-JSON-Tests/Devices/JsonDataItemEmptyNameOmissionTests.cs b/tests/MTConnect.NET-JSON-Tests/Devices/JsonDataItemEmptyNameOmissionTests.cs index e0629807f..d2ab318b5 100644 --- a/tests/MTConnect.NET-JSON-Tests/Devices/JsonDataItemEmptyNameOmissionTests.cs +++ b/tests/MTConnect.NET-JSON-Tests/Devices/JsonDataItemEmptyNameOmissionTests.cs @@ -26,6 +26,7 @@ namespace MTConnect.Tests.Json.Devices [Category("NameAttributeOmissionWhenUnsetOrEmpty")] public class JsonDataItemEmptyNameOmissionTests { + /// Pins the behaviour expressed by the test name: constructor with null name source does not serialize name key. [Test] public void Constructor_with_null_Name_source_does_not_serialize_name_key() { @@ -44,6 +45,7 @@ public void Constructor_with_null_Name_source_does_not_serialize_name_key() "Base JSON Probe DataItem must omit 'name' when source Name is null"); } + /// Pins the behaviour expressed by the test name: constructor with empty name source does not serialize name key. [Test] public void Constructor_with_empty_Name_source_does_not_serialize_name_key() { @@ -62,6 +64,7 @@ public void Constructor_with_empty_Name_source_does_not_serialize_name_key() "Base JSON Probe DataItem must omit 'name' when source Name is empty"); } + /// Pins the behaviour expressed by the test name: constructor with explicit name source serializes name key. [Test] public void Constructor_with_explicit_Name_source_serializes_name_key() { @@ -81,6 +84,7 @@ public void Constructor_with_explicit_Name_source_serializes_name_key() Assert.That(nameElement.GetString(), Is.EqualTo("temp")); } + /// Pins the behaviour expressed by the test name: constructor with typed data item unset name does not serialize name key. [Test] public void Constructor_with_typed_DataItem_unset_Name_does_not_serialize_name_key() { diff --git a/tests/MTConnect.NET-JSON-Tests/Devices/JsonDataItemNameAttributePinTests.cs b/tests/MTConnect.NET-JSON-Tests/Devices/JsonDataItemNameAttributePinTests.cs index c610800f7..eaf36b41c 100644 --- a/tests/MTConnect.NET-JSON-Tests/Devices/JsonDataItemNameAttributePinTests.cs +++ b/tests/MTConnect.NET-JSON-Tests/Devices/JsonDataItemNameAttributePinTests.cs @@ -30,6 +30,7 @@ namespace MTConnect.Tests.Json.Devices [Category("NameAttributeOmissionWhenUnsetOrEmpty")] public class JsonDataItemNameAttributePinTests { + /// Pins the behaviour expressed by the test name: name property carries json ignore when writing null attribute. [Test] public void Name_property_carries_JsonIgnore_WhenWritingNull_attribute() { @@ -41,6 +42,7 @@ public void Name_property_carries_JsonIgnore_WhenWritingNull_attribute() "JsonDataItem.Name [JsonIgnore] condition must be WhenWritingNull."); } + /// Pins the behaviour expressed by the test name: raw system text json serialise omits name when null. [Test] public void Raw_System_Text_Json_serialise_omits_name_when_null() { diff --git a/tests/MTConnect.NET-JSON-Tests/SanityTests.cs b/tests/MTConnect.NET-JSON-Tests/SanityTests.cs index b3fc04820..4ec94bc83 100644 --- a/tests/MTConnect.NET-JSON-Tests/SanityTests.cs +++ b/tests/MTConnect.NET-JSON-Tests/SanityTests.cs @@ -2,9 +2,11 @@ namespace MTConnect.NET_JSON_Tests { + /// Pins the behaviour expressed by the test name: sanity tests. [TestFixture] public class SanityTests { + /// Pins the behaviour expressed by the test name: project loads and references m t connect n e t j s o n. [Test] public void Project_loads_and_references_MTConnect_NET_JSON() { From 7a89455dce7047aa6ada91ec93dba9de5b70335b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:32:18 +0200 Subject: [PATCH 12/29] docs(mqttrelay-tests): author XML doc comments on test surface --- .../AsyncVoidGuardTests.cs | 12 ++++++++++++ .../AvailabilityTopicRegressionTests.cs | 2 ++ .../AvailabilityTopicTests.cs | 8 ++++++++ .../AvailabilityTopicValidationTests.cs | 9 +++++++++ .../LastSentSequencePersisterTests.cs | 8 ++++++++ .../MqttRelayLifecycleDisconnectTests.cs | 5 +++++ .../MqttRelayLifecycleStopTests.cs | 5 +++++ .../ObservationGrouperTests.cs | 6 ++++++ .../RelayBufferDiagnosticsTests.cs | 5 +++++ .../WorkerLoopExceptionLoggerTests.cs | 6 ++++++ 10 files changed, 66 insertions(+) diff --git a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AsyncVoidGuardTests.cs b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AsyncVoidGuardTests.cs index c63947165..ff032c365 100644 --- a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AsyncVoidGuardTests.cs +++ b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AsyncVoidGuardTests.cs @@ -33,6 +33,8 @@ namespace MTConnect.AgentModule.MqttRelay.Tests [TestFixture] public class AsyncVoidGuardTests { + /// Pins the behaviour expressed by the test name: run completes normally when body succeeds. + /// The result of the operation. [Test] public async Task Run_completes_normally_when_body_succeeds() { @@ -46,6 +48,8 @@ await AsyncVoidGuard.Run( "Successful body must not invoke the fault logger."); } + /// Pins the behaviour expressed by the test name: run routes synchronous throw to logger. + /// The result of the operation. [Test] public async Task Run_routes_synchronous_throw_to_logger() { @@ -58,6 +62,8 @@ await AsyncVoidGuard.Run( Assert.That(loggedFault, Is.EqualTo("sync throw")); } + /// Pins the behaviour expressed by the test name: run routes async throw to logger. + /// The result of the operation. [Test] public async Task Run_routes_async_throw_to_logger() { @@ -70,6 +76,8 @@ await AsyncVoidGuard.Run( Assert.That(loggedFault, Is.EqualTo("async throw")); } + /// Pins the behaviour expressed by the test name: run does not rethrow when logger is null. + /// The result of the operation. [Test] public async Task Run_does_not_rethrow_when_logger_is_null() { @@ -82,6 +90,8 @@ await AsyncVoidGuard.Run( Assert.Pass(); } + /// Pins the behaviour expressed by the test name: run does not rethrow when logger itself throws. + /// The result of the operation. [Test] public async Task Run_does_not_rethrow_when_logger_itself_throws() { @@ -94,6 +104,8 @@ await AsyncVoidGuard.Run( Assert.Pass(); } + /// Pins the behaviour expressed by the test name: run no ops when body is null. + /// The result of the operation. [Test] public async Task Run_no_ops_when_body_is_null() { diff --git a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicRegressionTests.cs b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicRegressionTests.cs index 9099d32e0..67586e957 100644 --- a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicRegressionTests.cs +++ b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicRegressionTests.cs @@ -29,6 +29,7 @@ namespace MTConnect.AgentModule.MqttRelay.Tests [TestFixture] public class AvailabilityTopicRegressionTests { + /// Pins the behaviour expressed by the test name: topic never contains probe segment for any inputs. [Test] public void Topic_never_contains_probe_segment_for_any_inputs() { @@ -75,6 +76,7 @@ public void Topic_never_contains_probe_segment_for_any_inputs() } } + /// Pins the behaviour expressed by the test name: agent segment is distinct from probe constant. [Test] public void Agent_segment_is_distinct_from_probe_constant() { diff --git a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicTests.cs b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicTests.cs index a2df94669..8b7723351 100644 --- a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicTests.cs +++ b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicTests.cs @@ -32,6 +32,7 @@ namespace MTConnect.AgentModule.MqttRelay.Tests [TestFixture] public class AvailabilityTopicTests { + /// Pins the behaviour expressed by the test name: build returns topic outside probe wildcard. [Test] public void Build_returns_topic_outside_probe_wildcard() { @@ -43,6 +44,7 @@ public void Build_returns_topic_outside_probe_wildcard() "MqttRelay availability topic must not fall under the Probe/# wildcard."); } + /// Pins the behaviour expressed by the test name: build uses dedicated agent segment. [Test] public void Build_uses_dedicated_agent_segment() { @@ -57,6 +59,7 @@ public void Build_uses_dedicated_agent_segment() Assert.That(topic, Is.EqualTo("MTConnect/Agent/agent-uuid-1/Available")); } + /// Pins the behaviour expressed by the test name: build preserves multi segment topic prefix. [Test] public void Build_preserves_multi_segment_topic_prefix() { @@ -72,30 +75,35 @@ public void Build_preserves_multi_segment_topic_prefix() Assert.That(topic, Does.Not.Contain("/Probe/")); } + /// Pins the behaviour expressed by the test name: build returns null when topic prefix is null. [Test] public void Build_returns_null_when_topic_prefix_is_null() { Assert.That(AvailabilityTopic.Build(null, "agent-uuid-1"), Is.Null); } + /// Pins the behaviour expressed by the test name: build returns null when topic prefix is empty. [Test] public void Build_returns_null_when_topic_prefix_is_empty() { Assert.That(AvailabilityTopic.Build(string.Empty, "agent-uuid-1"), Is.Null); } + /// Pins the behaviour expressed by the test name: build returns null when agent uuid is null. [Test] public void Build_returns_null_when_agent_uuid_is_null() { Assert.That(AvailabilityTopic.Build("MTConnect", null), Is.Null); } + /// Pins the behaviour expressed by the test name: build returns null when agent uuid is empty. [Test] public void Build_returns_null_when_agent_uuid_is_empty() { Assert.That(AvailabilityTopic.Build("MTConnect", string.Empty), Is.Null); } + /// Pins the behaviour expressed by the test name: available segment constant pins trailing topic segment. [Test] public void AvailableSegment_constant_pins_trailing_topic_segment() { diff --git a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicValidationTests.cs b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicValidationTests.cs index 072115698..7410e1a70 100644 --- a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicValidationTests.cs +++ b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/AvailabilityTopicValidationTests.cs @@ -26,6 +26,9 @@ namespace MTConnect.AgentModule.MqttRelay.Tests [TestFixture] public class AvailabilityTopicValidationTests { + /// Pins the behaviour expressed by the test name: build returns null when reserved character present. + /// The topic prefix. + /// The agent uuid. [TestCase("MTConnect+", "agent-uuid-1")] [TestCase("MTConnect#", "agent-uuid-1")] [TestCase("MTConnect\0", "agent-uuid-1")] @@ -41,6 +44,9 @@ public void Build_returns_null_when_reserved_character_present( $"Build({topicPrefix}, {agentUuid}) should reject MQTT-reserved characters."); } + /// Pins the behaviour expressed by the test name: build returns null when input is whitespace only. + /// The topic prefix. + /// The agent uuid. [TestCase(" ", "agent-uuid-1")] [TestCase("MTConnect", " ")] public void Build_returns_null_when_input_is_whitespace_only( @@ -56,6 +62,7 @@ public void Build_returns_null_when_input_is_whitespace_only( $"Build({topicPrefix}, {agentUuid}) should reject whitespace-only input."); } + /// Pins the behaviour expressed by the test name: build rejects slash inside agent uuid segment. [Test] public void Build_rejects_slash_inside_agent_uuid_segment() { @@ -67,6 +74,7 @@ public void Build_rejects_slash_inside_agent_uuid_segment() Is.Null); } + /// Pins the behaviour expressed by the test name: build strips leading slash from topic prefix. [Test] public void Build_strips_leading_slash_from_topic_prefix() { @@ -79,6 +87,7 @@ public void Build_strips_leading_slash_from_topic_prefix() Is.EqualTo("MTConnect/Agent/agent-1/Available")); } + /// Pins the behaviour expressed by the test name: build strips trailing slash from topic prefix. [Test] public void Build_strips_trailing_slash_from_topic_prefix() { diff --git a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/LastSentSequencePersisterTests.cs b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/LastSentSequencePersisterTests.cs index 95b996a0a..7fccbc448 100644 --- a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/LastSentSequencePersisterTests.cs +++ b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/LastSentSequencePersisterTests.cs @@ -23,6 +23,7 @@ namespace MTConnect.AgentModule.MqttRelay.Tests [TestFixture] public class LastSentSequencePersisterTests { + /// Pins the behaviour expressed by the test name: update marks dirty and round trips through read. [Test] public void Update_marks_dirty_and_round_trips_through_read() { @@ -35,6 +36,7 @@ public void Update_marks_dirty_and_round_trips_through_read() "An in-memory update must mark the persister dirty so the caller knows to flush."); } + /// Pins the behaviour expressed by the test name: read does not clear dirty bit. [Test] public void Read_does_not_clear_dirty_bit() { @@ -47,6 +49,7 @@ public void Read_does_not_clear_dirty_bit() "Read must not clear dirty: only Flush establishes durable persistence."); } + /// Pins the behaviour expressed by the test name: try flush writes only when dirty and clears dirty on success. [Test] public void TryFlush_writes_only_when_dirty_and_clears_dirty_on_success() { @@ -63,6 +66,7 @@ public void TryFlush_writes_only_when_dirty_and_clears_dirty_on_success() "After a successful flush the persister must be clean so the next timer tick does not redundantly write."); } + /// Pins the behaviour expressed by the test name: try flush no ops when not dirty. [Test] public void TryFlush_no_ops_when_not_dirty() { @@ -76,6 +80,7 @@ public void TryFlush_no_ops_when_not_dirty() "A clean persister must not invoke the writer; that would burn IOPS for no progress."); } + /// Pins the behaviour expressed by the test name: try flush keeps dirty when writer throws. [Test] public void TryFlush_keeps_dirty_when_writer_throws() { @@ -92,6 +97,7 @@ public void TryFlush_keeps_dirty_when_writer_throws() Assert.That(persister.Read(), Is.EqualTo(123UL)); } + /// Pins the behaviour expressed by the test name: update is a last write wins overwrite. [Test] public void Update_is_a_last_write_wins_overwrite() { @@ -103,6 +109,7 @@ public void Update_is_a_last_write_wins_overwrite() "Last write wins; the persister is not a max-watermark."); } + /// Pins the behaviour expressed by the test name: initialize seeds value without marking dirty. [Test] public void Initialize_seeds_value_without_marking_dirty() { @@ -118,6 +125,7 @@ public void Initialize_seeds_value_without_marking_dirty() "Initialize seeds the in-memory value from disk and must not request a redundant flush."); } + /// Pins the behaviour expressed by the test name: try flush no ops when writer is null. [Test] public void TryFlush_no_ops_when_writer_is_null() { diff --git a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/MqttRelayLifecycleDisconnectTests.cs b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/MqttRelayLifecycleDisconnectTests.cs index 44c95d47e..d2611d524 100644 --- a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/MqttRelayLifecycleDisconnectTests.cs +++ b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/MqttRelayLifecycleDisconnectTests.cs @@ -29,6 +29,7 @@ namespace MTConnect.AgentModule.MqttRelay.Tests [TestFixture] public class MqttRelayLifecycleDisconnectTests { + /// Pins the behaviour expressed by the test name: disconnect with timeout returns when disconnect completes. [Test] public void DisconnectWithTimeout_returns_when_disconnect_completes() { @@ -45,6 +46,7 @@ public void DisconnectWithTimeout_returns_when_disconnect_completes() "Successful disconnect must not invoke the fault logger."); } + /// Pins the behaviour expressed by the test name: disconnect with timeout logs fault when disconnect throws. [Test] public void DisconnectWithTimeout_logs_fault_when_disconnect_throws() { @@ -59,6 +61,7 @@ public void DisconnectWithTimeout_logs_fault_when_disconnect_throws() "A faulted disconnect Task must surface its exception to the logger."); } + /// Pins the behaviour expressed by the test name: disconnect with timeout returns after timeout when disconnect hangs. [Test] public void DisconnectWithTimeout_returns_after_timeout_when_disconnect_hangs() { @@ -77,6 +80,7 @@ public void DisconnectWithTimeout_returns_after_timeout_when_disconnect_hangs() "Hung disconnect must bail out near the configured timeout."); } + /// Pins the behaviour expressed by the test name: disconnect with timeout does not throw when disconnect factory throws synchronously. [Test] public void DisconnectWithTimeout_does_not_throw_when_disconnect_factory_throws_synchronously() { @@ -93,6 +97,7 @@ public void DisconnectWithTimeout_does_not_throw_when_disconnect_factory_throws_ Assert.That(loggedFault, Is.EqualTo("sync throw")); } + /// Pins the behaviour expressed by the test name: disconnect with timeout no ops when disconnect factory is null. [Test] public void DisconnectWithTimeout_no_ops_when_disconnect_factory_is_null() { diff --git a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/MqttRelayLifecycleStopTests.cs b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/MqttRelayLifecycleStopTests.cs index d0c2af405..061d132ea 100644 --- a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/MqttRelayLifecycleStopTests.cs +++ b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/MqttRelayLifecycleStopTests.cs @@ -24,6 +24,7 @@ namespace MTConnect.AgentModule.MqttRelay.Tests [TestFixture] public class MqttRelayLifecycleStopTests { + /// Pins the behaviour expressed by the test name: stop servers does not throw when both servers null. [Test] public void StopServers_does_not_throw_when_both_servers_null() { @@ -34,6 +35,7 @@ public void StopServers_does_not_throw_when_both_servers_null() () => MqttRelayLifecycle.StopServers(documentStop: null, entityStop: null)); } + /// Pins the behaviour expressed by the test name: stop servers invokes document stop when provided. [Test] public void StopServers_invokes_document_stop_when_provided() { @@ -46,6 +48,7 @@ public void StopServers_invokes_document_stop_when_provided() "Document-mode shutdown must invoke the document-server stop action."); } + /// Pins the behaviour expressed by the test name: stop servers invokes entity stop when provided. [Test] public void StopServers_invokes_entity_stop_when_provided() { @@ -58,6 +61,7 @@ public void StopServers_invokes_entity_stop_when_provided() "Entity-mode shutdown must invoke the entity-server stop action."); } + /// Pins the behaviour expressed by the test name: stop servers invokes both when both provided. [Test] public void StopServers_invokes_both_when_both_provided() { @@ -72,6 +76,7 @@ public void StopServers_invokes_both_when_both_provided() Assert.That(entityStopped, Is.True); } + /// Pins the behaviour expressed by the test name: stop servers swallows document stop exception and runs entity stop. [Test] public void StopServers_swallows_document_stop_exception_and_runs_entity_stop() { diff --git a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/ObservationGrouperTests.cs b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/ObservationGrouperTests.cs index d411f4532..ce4b91819 100644 --- a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/ObservationGrouperTests.cs +++ b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/ObservationGrouperTests.cs @@ -38,12 +38,14 @@ namespace MTConnect.AgentModule.MqttRelay.Tests [TestFixture] public class ObservationGrouperTests { + /// Pins the behaviour expressed by the test name: group by data item returns empty when input null. [Test] public void GroupByDataItem_returns_empty_when_input_null() { Assert.That(ObservationGrouper.GroupByDataItem(null), Is.Empty); } + /// Pins the behaviour expressed by the test name: group by data item returns empty when input empty. [Test] public void GroupByDataItem_returns_empty_when_input_empty() { @@ -52,6 +54,7 @@ public void GroupByDataItem_returns_empty_when_input_empty() Is.Empty); } + /// Pins the behaviour expressed by the test name: group by data item groups observations by data item id. [Test] public void GroupByDataItem_groups_observations_by_data_item_id() { @@ -78,6 +81,7 @@ public void GroupByDataItem_groups_observations_by_data_item_id() Assert.That(groupC.Select(o => o.Sequence), Is.EquivalentTo(new ulong[] { 4 })); } + /// Pins the behaviour expressed by the test name: group by data item iterates source exactly once. [Test] public void GroupByDataItem_iterates_source_exactly_once() { @@ -103,6 +107,7 @@ IEnumerable Source() Assert.That(groups, Has.Count.EqualTo(2)); } + /// Pins the behaviour expressed by the test name: group by data item preserves first seen order per group. [Test] public void GroupByDataItem_preserves_first_seen_order_per_group() { @@ -121,6 +126,7 @@ public void GroupByDataItem_preserves_first_seen_order_per_group() Is.EqualTo(new ulong[] { 10, 11, 12 })); } + /// Pins the behaviour expressed by the test name: group by data item handles null data item id as distinct group. [Test] public void GroupByDataItem_handles_null_data_item_id_as_distinct_group() { diff --git a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/RelayBufferDiagnosticsTests.cs b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/RelayBufferDiagnosticsTests.cs index 2c28d15aa..d880d7f41 100644 --- a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/RelayBufferDiagnosticsTests.cs +++ b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/RelayBufferDiagnosticsTests.cs @@ -24,6 +24,7 @@ namespace MTConnect.AgentModule.MqttRelay.Tests [TestFixture] public class RelayBufferDiagnosticsTests { + /// Pins the behaviour expressed by the test name: compute missed returns zero when last sent above to. [Test] public void ComputeMissed_returns_zero_when_last_sent_above_to() { @@ -33,6 +34,7 @@ public void ComputeMissed_returns_zero_when_last_sent_above_to() "Underflow guard: when lastSent > to, missed must be 0."); } + /// Pins the behaviour expressed by the test name: compute missed returns zero when last sent equals to. [Test] public void ComputeMissed_returns_zero_when_last_sent_equals_to() { @@ -41,6 +43,7 @@ public void ComputeMissed_returns_zero_when_last_sent_equals_to() Is.Zero); } + /// Pins the behaviour expressed by the test name: compute missed returns difference when last sent below to. [Test] public void ComputeMissed_returns_difference_when_last_sent_below_to() { @@ -49,6 +52,7 @@ public void ComputeMissed_returns_difference_when_last_sent_below_to() Is.EqualTo(75L)); } + /// Pins the behaviour expressed by the test name: compute missed handles zero last sent. [Test] public void ComputeMissed_handles_zero_last_sent() { @@ -57,6 +61,7 @@ public void ComputeMissed_handles_zero_last_sent() Is.EqualTo(100L)); } + /// Pins the behaviour expressed by the test name: compute missed round trips long max value difference. [Test] public void ComputeMissed_round_trips_long_max_value_difference() { diff --git a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/WorkerLoopExceptionLoggerTests.cs b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/WorkerLoopExceptionLoggerTests.cs index dcd4c0c04..093b158ee 100644 --- a/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/WorkerLoopExceptionLoggerTests.cs +++ b/tests/MTConnect.NET-AgentModule-MqttRelay-Tests/WorkerLoopExceptionLoggerTests.cs @@ -31,6 +31,7 @@ namespace MTConnect.AgentModule.MqttRelay.Tests [TestFixture] public class WorkerLoopExceptionLoggerTests { + /// Pins the behaviour expressed by the test name: log skips task canceled exception. [Test] public void Log_skips_TaskCanceledException() { @@ -44,6 +45,7 @@ public void Log_skips_TaskCanceledException() "TaskCanceledException is the orderly-shutdown signal; do not spam the log on every stop."); } + /// Pins the behaviour expressed by the test name: log writes unexpected exception to callback. [Test] public void Log_writes_unexpected_exception_to_callback() { @@ -58,6 +60,7 @@ public void Log_writes_unexpected_exception_to_callback() "The unexpected-exception message must include the exception text so the operator can diagnose the defect."); } + /// Pins the behaviour expressed by the test name: log includes exception type name. [Test] public void Log_includes_exception_type_name() { @@ -71,6 +74,7 @@ public void Log_includes_exception_type_name() "Type name aids in classifying the defect from log scrapes."); } + /// Pins the behaviour expressed by the test name: log no ops when exception is null. [Test] public void Log_no_ops_when_exception_is_null() { @@ -84,6 +88,7 @@ public void Log_no_ops_when_exception_is_null() "A null exception cannot be logged usefully; do not invoke the callback."); } + /// Pins the behaviour expressed by the test name: log no ops when callback is null. [Test] public void Log_no_ops_when_callback_is_null() { @@ -95,6 +100,7 @@ public void Log_no_ops_when_callback_is_null() onLog: null)); } + /// Pins the behaviour expressed by the test name: log treats subclass of task canceled exception as cancellation. [Test] public void Log_treats_subclass_of_TaskCanceledException_as_cancellation() { From 718fec9964bfeefb771b1762f02323e402de3c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:34:04 +0200 Subject: [PATCH 13/29] docs(integration-tests): author XML doc comments on test surface --- .../ClientAgentCommunicationTests.cs | 12 ++++++++++++ .../GenerateDevicesXmlTests.cs | 4 ++++ ...ConfigurationPolymorphicHttpProbeWorkflowTests.cs | 4 ++++ .../Workflows/HttpAssetWorkflowTests.cs | 7 +++++++ .../Workflows/HttpProbeWorkflowTests.cs | 7 +++++++ .../JsonMqttProbeEnvelopeIntegrationTests.cs | 8 ++++++++ .../Workflows/MqttBrokerFixture.cs | 10 ++++++++++ .../Workflows/MqttRelayWorkflowTests.cs | 8 ++++++++ 8 files changed, 60 insertions(+) diff --git a/tests/MTConnect.NET-Integration-Tests/ClientAgentCommunicationTests.cs b/tests/MTConnect.NET-Integration-Tests/ClientAgentCommunicationTests.cs index d5f8660d9..15ff6af8a 100644 --- a/tests/MTConnect.NET-Integration-Tests/ClientAgentCommunicationTests.cs +++ b/tests/MTConnect.NET-Integration-Tests/ClientAgentCommunicationTests.cs @@ -26,6 +26,7 @@ namespace MTConnect.Tests.Integration { + /// Represents the m t agent fixture. public class MTAgentFixture { // Hands out a distinct OS-assigned free loopback TCP port on each call. @@ -35,6 +36,8 @@ public class MTAgentFixture // own port, so no two tests (in this run or a concurrent/back-to-back // run) ever contend for a fixed number — the start-up "Address already // in use" race that a hard-coded port causes is removed at the root. + /// Runs the get free port operation. + /// The result of the operation. public static int GetFreePort() { using var probe = new System.Net.Sockets.Socket( @@ -47,6 +50,7 @@ public static int GetFreePort() } } + /// Represents the client agent communication tests. public class ClientAgentCommunicationTests : IClassFixture, IDisposable { #region Fields @@ -114,6 +118,9 @@ public class ClientAgentCommunicationTests : IClassFixture, IDis #endregion + /// Initialises a new instance of the client agent communication tests type. + /// The fixture. + /// The test output helper. public ClientAgentCommunicationTests( MTAgentFixture fixture, ITestOutputHelper testOutputHelper) @@ -256,6 +263,7 @@ private void WaitForServerReady(int port, string deviceName) + (lastError != null ? $" (last error: {lastError.Message})." : ".")); } + /// Runs the dispose operation. public void Dispose() { _agent.Stop(); @@ -467,6 +475,8 @@ internal static void GenerateDevicesXml( #endregion + /// Pins the behaviour expressed by the test name: get current field should return updated value. + /// The result of the operation. [Fact] public async Task GetCurrentFieldShouldReturnUpdatedValue() { @@ -521,6 +531,8 @@ public async Task GetCurrentFieldShouldReturnUpdatedValue() Assert.Equal("SuperProg42", current); } + /// Pins the behaviour expressed by the test name: wait for sample should succeed after first item is sent. + /// The result of the operation. [Fact] public async Task WaitForSampleShouldSucceedAfterFirstItemIsSent() { diff --git a/tests/MTConnect.NET-Integration-Tests/GenerateDevicesXmlTests.cs b/tests/MTConnect.NET-Integration-Tests/GenerateDevicesXmlTests.cs index 18fb5f882..ba58f040d 100644 --- a/tests/MTConnect.NET-Integration-Tests/GenerateDevicesXmlTests.cs +++ b/tests/MTConnect.NET-Integration-Tests/GenerateDevicesXmlTests.cs @@ -9,10 +9,12 @@ namespace MTConnect.Tests.Integration // fileName argument; earlier revisions hard-coded "devices.xml" inside // File.Create(...) so the argument was silently ignored. These tests pin // the contract that the file is created at the requested path. + /// Represents the generate devices xml tests. public class GenerateDevicesXmlTests : IDisposable { private readonly string _tempDir; + /// Initialises a new instance of the generate devices xml tests type. public GenerateDevicesXmlTests() { _tempDir = Path.Combine( @@ -21,6 +23,7 @@ public GenerateDevicesXmlTests() Directory.CreateDirectory(_tempDir); } + /// Runs the dispose operation. public void Dispose() { try @@ -36,6 +39,7 @@ public void Dispose() } } + /// Pins the behaviour expressed by the test name: generate devices xml honours file name argument. [Fact] public void GenerateDevicesXml_HonoursFileNameArgument() { diff --git a/tests/MTConnect.NET-Integration-Tests/Workflows/ConfigurationPolymorphicHttpProbeWorkflowTests.cs b/tests/MTConnect.NET-Integration-Tests/Workflows/ConfigurationPolymorphicHttpProbeWorkflowTests.cs index aa50e16bd..65184e412 100644 --- a/tests/MTConnect.NET-Integration-Tests/Workflows/ConfigurationPolymorphicHttpProbeWorkflowTests.cs +++ b/tests/MTConnect.NET-Integration-Tests/Workflows/ConfigurationPolymorphicHttpProbeWorkflowTests.cs @@ -64,6 +64,7 @@ public class ConfigurationPolymorphicHttpProbeWorkflowTests // ---------------- W08: Motion + AxisDataSet ---------------- + /// Pins the behaviour expressed by the test name: probe returns axis data set round tripped through h t t p. [Fact] public void Probe_returns_AxisDataSet_round_tripped_through_HTTP() { @@ -96,6 +97,7 @@ public void Probe_returns_AxisDataSet_round_tripped_through_HTTP() // ---------------- W09: CoordinateSystem + OriginDataSet ---------------- + /// Pins the behaviour expressed by the test name: probe returns origin data set round tripped through h t t p. [Fact] public void Probe_returns_OriginDataSet_round_tripped_through_HTTP() { @@ -132,6 +134,7 @@ public void Probe_returns_OriginDataSet_round_tripped_through_HTTP() // ---------------- W10: Transformation + RotationDataSet ---------------- + /// Pins the behaviour expressed by the test name: probe returns rotation data set round tripped through h t t p. [Fact] public void Probe_returns_RotationDataSet_round_tripped_through_HTTP() { @@ -169,6 +172,7 @@ public void Probe_returns_RotationDataSet_round_tripped_through_HTTP() // ---------------- negative-path: simple Axis still narrows correctly ---------------- + /// Pins the behaviour expressed by the test name: probe returns simple axis not narrowed to data set. [Fact] public void Probe_returns_simple_Axis_not_narrowed_to_DataSet() { diff --git a/tests/MTConnect.NET-Integration-Tests/Workflows/HttpAssetWorkflowTests.cs b/tests/MTConnect.NET-Integration-Tests/Workflows/HttpAssetWorkflowTests.cs index 2a5f3b118..cf69bbbfb 100644 --- a/tests/MTConnect.NET-Integration-Tests/Workflows/HttpAssetWorkflowTests.cs +++ b/tests/MTConnect.NET-Integration-Tests/Workflows/HttpAssetWorkflowTests.cs @@ -25,6 +25,7 @@ namespace MTConnect.Tests.Integration.Workflows // Boots an in-process agent + HTTP server, seeds it with a CuttingTool // asset via the broker's AddAsset path, and asserts /assets returns // an envelope referencing the asset's id. + /// Represents the http asset workflow tests. [Trait("Category", "E2E")] public sealed class HttpAssetWorkflowTests : IDisposable { @@ -35,6 +36,7 @@ public sealed class HttpAssetWorkflowTests : IDisposable private const string DeviceUuid = "workflow-asset-device"; private const string DeviceName = "WorkflowAssetDevice"; + /// Initialises a new instance of the http asset workflow tests type. public HttpAssetWorkflowTests() { _port = AllocateLoopbackPort(); @@ -83,12 +85,15 @@ public HttpAssetWorkflowTests() WaitForListener("127.0.0.1", _port, TimeSpan.FromSeconds(30), () => startupException); } + /// Runs the dispose operation. public void Dispose() { _server?.Stop(); _agent?.Stop(); } + /// Pins the behaviour expressed by the test name: asset request returns seeded asset id. + /// The result of the operation. [Fact] public async Task Asset_request_returns_seeded_asset_id() { @@ -108,6 +113,8 @@ public async Task Asset_request_returns_seeded_asset_id() Assert.Contains(AssetId, body); } + /// Pins the behaviour expressed by the test name: specific asset id request returns targeted asset. + /// The result of the operation. [Fact] public async Task Specific_asset_id_request_returns_targeted_asset() { diff --git a/tests/MTConnect.NET-Integration-Tests/Workflows/HttpProbeWorkflowTests.cs b/tests/MTConnect.NET-Integration-Tests/Workflows/HttpProbeWorkflowTests.cs index 46950c247..132ebba1e 100644 --- a/tests/MTConnect.NET-Integration-Tests/Workflows/HttpProbeWorkflowTests.cs +++ b/tests/MTConnect.NET-Integration-Tests/Workflows/HttpProbeWorkflowTests.cs @@ -28,6 +28,7 @@ namespace MTConnect.Tests.Integration.Workflows // ClientAgentCommunicationTests fixture uses, and asserts the /probe // endpoint returns a 200 with a devices envelope referencing the // seeded device by uuid + name. + /// Represents the http probe workflow tests. [Trait("Category", "E2E")] public sealed class HttpProbeWorkflowTests : IDisposable { @@ -37,6 +38,7 @@ public sealed class HttpProbeWorkflowTests : IDisposable private readonly string _machineId; private readonly string _machineName; + /// Initialises a new instance of the http probe workflow tests type. public HttpProbeWorkflowTests() { // Pick a free loopback port at fixture-creation time so @@ -93,12 +95,15 @@ public HttpProbeWorkflowTests() } } + /// Runs the dispose operation. public void Dispose() { _server?.Stop(); _agent?.Stop(); } + /// Pins the behaviour expressed by the test name: probe returns seeded device. + /// The result of the operation. [Fact] public async Task Probe_returns_seeded_device() { @@ -120,6 +125,8 @@ public async Task Probe_returns_seeded_device() Assert.Contains(_machineId, body); } + /// Pins the behaviour expressed by the test name: probe with unknown device returns error envelope. + /// The result of the operation. [Fact] public async Task Probe_with_unknown_device_returns_error_envelope() { diff --git a/tests/MTConnect.NET-Integration-Tests/Workflows/JsonMqttProbeEnvelopeIntegrationTests.cs b/tests/MTConnect.NET-Integration-Tests/Workflows/JsonMqttProbeEnvelopeIntegrationTests.cs index fcb89b58a..a12a0354b 100644 --- a/tests/MTConnect.NET-Integration-Tests/Workflows/JsonMqttProbeEnvelopeIntegrationTests.cs +++ b/tests/MTConnect.NET-Integration-Tests/Workflows/JsonMqttProbeEnvelopeIntegrationTests.cs @@ -42,6 +42,7 @@ namespace MTConnect.Tests.Integration.Workflows // 5029-5051): Agent (minOccurs=0, maxOccurs=1) and Device // (minOccurs=1, maxOccurs=unbounded) are SEPARATE named child // elements within the DevicesType sequence. + /// Represents the json mqtt probe envelope integration tests. [Trait("Category", "RequiresDocker")] public sealed class JsonMqttProbeEnvelopeIntegrationTests : IClassFixture, IDisposable @@ -64,6 +65,8 @@ public sealed class JsonMqttProbeEnvelopeIntegrationTests private readonly object _module; private readonly MethodInfo _stopMethod; + /// Initialises a new instance of the json mqtt probe envelope integration tests type. + /// The broker. public JsonMqttProbeEnvelopeIntegrationTests(MqttBrokerFixture broker) { _broker = broker; @@ -107,6 +110,7 @@ public JsonMqttProbeEnvelopeIntegrationTests(MqttBrokerFixture broker) startMethod.Invoke(_module, new object[] { true }); } + /// Runs the dispose operation. public void Dispose() { try { _stopMethod.Invoke(_module, null); } @@ -115,6 +119,8 @@ public void Dispose() } + /// Pins the behaviour expressed by the test name: probe envelope multi device round trip preserves every device. + /// The result of the operation. [Fact] public async Task Probe_envelope_multi_device_round_trip_preserves_every_device() { @@ -211,6 +217,8 @@ await subscriber.SubscribeAsync( } + /// Pins the behaviour expressed by the test name: probe envelope round trip through formatter preserves agent name case. + /// The result of the operation. [Fact] public async Task Probe_envelope_round_trip_through_formatter_preserves_Agent_name_case() { diff --git a/tests/MTConnect.NET-Integration-Tests/Workflows/MqttBrokerFixture.cs b/tests/MTConnect.NET-Integration-Tests/Workflows/MqttBrokerFixture.cs index 2cc85bad7..db34f9beb 100644 --- a/tests/MTConnect.NET-Integration-Tests/Workflows/MqttBrokerFixture.cs +++ b/tests/MTConnect.NET-Integration-Tests/Workflows/MqttBrokerFixture.cs @@ -20,18 +20,26 @@ namespace MTConnect.Tests.Integration.Workflows // MTConnectMqttRelay implements. // - https://mqtt.org/mqtt-specification/ — the wire protocol that the // Testcontainers Mosquitto + the in-process MQTTnet client speak. + /// Represents the mqtt broker fixture. public sealed class MqttBrokerFixture : IAsyncLifetime { + /// The image tag. public const string ImageTag = "eclipse-mosquitto:2.0.22"; private const int InternalPort = 1883; private IContainer? _container; + /// Gets or sets the host. public string Host => _container?.Hostname ?? "127.0.0.1"; + /// Runs the port operation. + /// The internal port. + /// The result of the operation. public int Port => _container?.GetMappedPublicPort(InternalPort) ?? throw new InvalidOperationException("Container has not been started."); + /// Runs the initialize async operation. + /// The result of the operation. public async Task InitializeAsync() { // Mosquitto 2.x refuses anonymous remote connections by default. @@ -61,6 +69,8 @@ public async Task InitializeAsync() await _container.StartAsync().ConfigureAwait(false); } + /// Runs the dispose async operation. + /// The result of the operation. public async Task DisposeAsync() { if (_container != null) diff --git a/tests/MTConnect.NET-Integration-Tests/Workflows/MqttRelayWorkflowTests.cs b/tests/MTConnect.NET-Integration-Tests/Workflows/MqttRelayWorkflowTests.cs index 78ab78cdc..371559792 100644 --- a/tests/MTConnect.NET-Integration-Tests/Workflows/MqttRelayWorkflowTests.cs +++ b/tests/MTConnect.NET-Integration-Tests/Workflows/MqttRelayWorkflowTests.cs @@ -38,6 +38,7 @@ namespace MTConnect.Tests.Integration.Workflows // fires. The test waits for that envelope to land on the subscriber // and inspects the payload to confirm it carries the seeded // observation. + /// Represents the mqtt relay workflow tests. [Trait("Category", "RequiresDocker")] public sealed class MqttRelayWorkflowTests : IClassFixture, IDisposable { @@ -53,6 +54,8 @@ public sealed class MqttRelayWorkflowTests : IClassFixture, I private readonly MethodInfo _startMethod; private readonly MethodInfo _stopMethod; + /// Initialises a new instance of the mqtt relay workflow tests type. + /// The broker. public MqttRelayWorkflowTests(MqttBrokerFixture broker) { _broker = broker; @@ -98,6 +101,7 @@ public MqttRelayWorkflowTests(MqttBrokerFixture broker) _startMethod.Invoke(_module, new object[] { true }); } + /// Runs the dispose operation. public void Dispose() { try { _stopMethod.Invoke(_module, null); } @@ -105,6 +109,8 @@ public void Dispose() _agent.Stop(); } + /// Pins the behaviour expressed by the test name: agent publishes observation consumer receives same payload. + /// The result of the operation. [Fact] public async Task Agent_publishes_observation_consumer_receives_same_payload() { @@ -169,6 +175,8 @@ await subscriber.SubscribeAsync( Assert.Contains(InjectedSentinel, payload); } + /// Pins the behaviour expressed by the test name: consumer disconnects mid publish agent does not lose observations. + /// The result of the operation. [Fact] public async Task Consumer_disconnects_mid_publish_agent_does_not_lose_observations() { From dacb3be6ef63be6e8e633116e7214641bce46561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:36:23 +0200 Subject: [PATCH 14/29] fix(integration-tests): replace stub param tag with Port summary --- .../Workflows/MqttBrokerFixture.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/MTConnect.NET-Integration-Tests/Workflows/MqttBrokerFixture.cs b/tests/MTConnect.NET-Integration-Tests/Workflows/MqttBrokerFixture.cs index db34f9beb..b25079208 100644 --- a/tests/MTConnect.NET-Integration-Tests/Workflows/MqttBrokerFixture.cs +++ b/tests/MTConnect.NET-Integration-Tests/Workflows/MqttBrokerFixture.cs @@ -32,9 +32,7 @@ public sealed class MqttBrokerFixture : IAsyncLifetime /// Gets or sets the host. public string Host => _container?.Hostname ?? "127.0.0.1"; - /// Runs the port operation. - /// The internal port. - /// The result of the operation. + /// Gets the mapped public port the broker is listening on. public int Port => _container?.GetMappedPublicPort(InternalPort) ?? throw new InvalidOperationException("Container has not been started."); From 03e35c5cbe6a0d64b6e74440cdc28dd48e8efa8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:37:46 +0200 Subject: [PATCH 15/29] docs(shdr-tests): author XML doc comments on test surface --- tests/MTConnect.NET-SHDR-Tests/DataItems.cs | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/MTConnect.NET-SHDR-Tests/DataItems.cs b/tests/MTConnect.NET-SHDR-Tests/DataItems.cs index ff85cb8a5..957ba482b 100644 --- a/tests/MTConnect.NET-SHDR-Tests/DataItems.cs +++ b/tests/MTConnect.NET-SHDR-Tests/DataItems.cs @@ -10,6 +10,7 @@ namespace MTConnect.Tests.Shdr { + /// Represents the data item format. public class DataItemFormat { private const long BeforeY2KUnix = 9466847990000000; @@ -45,6 +46,7 @@ public class DataItemFormat #region "Single" + /// Pins the behaviour expressed by the test name: format check single. [Test] public void FormatCheckSingle() { @@ -63,6 +65,7 @@ public void FormatCheckSingle() } } + /// Pins the behaviour expressed by the test name: format check single timestamp. [Test] public void FormatCheckSingleTimestamp() { @@ -82,6 +85,7 @@ public void FormatCheckSingleTimestamp() } + /// Pins the behaviour expressed by the test name: format check single quotes. [Test] public void FormatCheckSingleQuotes() { @@ -100,6 +104,7 @@ public void FormatCheckSingleQuotes() } } + /// Pins the behaviour expressed by the test name: format check single double quotes. [Test] public void FormatCheckSingleDoubleQuotes() { @@ -118,6 +123,7 @@ public void FormatCheckSingleDoubleQuotes() } } + /// Pins the behaviour expressed by the test name: format check single pipe. [Test] public void FormatCheckSinglePipe() { @@ -136,6 +142,7 @@ public void FormatCheckSinglePipe() } } + /// Pins the behaviour expressed by the test name: format check single null. [Test] public void FormatCheckSingleNull() { @@ -154,6 +161,7 @@ public void FormatCheckSingleNull() } } + /// Pins the behaviour expressed by the test name: format check single empty. [Test] public void FormatCheckSingleEmpty() { @@ -172,6 +180,7 @@ public void FormatCheckSingleEmpty() } } + /// Pins the behaviour expressed by the test name: format check single whitespace. [Test] public void FormatCheckSingleWhitespace() { @@ -190,6 +199,7 @@ public void FormatCheckSingleWhitespace() } } + /// Pins the behaviour expressed by the test name: format check single leading whitespace. [Test] public void FormatCheckSingleLeadingWhitespace() { @@ -208,6 +218,7 @@ public void FormatCheckSingleLeadingWhitespace() } } + /// Pins the behaviour expressed by the test name: format check single trailing whitespace. [Test] public void FormatCheckSingleTrailingWhitespace() { @@ -227,6 +238,7 @@ public void FormatCheckSingleTrailingWhitespace() } + /// Pins the behaviour expressed by the test name: format check single duration. [Test] public void FormatCheckSingleDuration() { @@ -246,6 +258,7 @@ public void FormatCheckSingleDuration() } } + /// Pins the behaviour expressed by the test name: format check single duration timestamp. [Test] public void FormatCheckSingleDurationTimestamp() { @@ -266,6 +279,7 @@ public void FormatCheckSingleDurationTimestamp() } + /// Pins the behaviour expressed by the test name: format check single reset triggered. [Test] public void FormatCheckSingleResetTriggered() { @@ -285,6 +299,7 @@ public void FormatCheckSingleResetTriggered() } } + /// Pins the behaviour expressed by the test name: format check single reset triggered timestamp. [Test] public void FormatCheckSingleResetTriggeredTimestamp() { @@ -305,6 +320,7 @@ public void FormatCheckSingleResetTriggeredTimestamp() } + /// Pins the behaviour expressed by the test name: format check single reset triggered duration. [Test] public void FormatCheckSingleResetTriggeredDuration() { @@ -325,6 +341,7 @@ public void FormatCheckSingleResetTriggeredDuration() } } + /// Pins the behaviour expressed by the test name: format check single reset triggered duration timestamp. [Test] public void FormatCheckSingleResetTriggeredDurationTimestamp() { @@ -349,6 +366,7 @@ public void FormatCheckSingleResetTriggeredDurationTimestamp() #region "Multiple" + /// Pins the behaviour expressed by the test name: format check multiple. [Test] public void FormatCheckMultiple() { @@ -371,6 +389,7 @@ public void FormatCheckMultiple() } } + /// Pins the behaviour expressed by the test name: format check multiple timestamps. [Test] public void FormatCheckMultipleTimestamps() { @@ -393,6 +412,7 @@ public void FormatCheckMultipleTimestamps() } } + /// Pins the behaviour expressed by the test name: format check multiple different timestamps. [Test] public void FormatCheckMultipleDifferentTimestamps() { @@ -416,6 +436,7 @@ public void FormatCheckMultipleDifferentTimestamps() } + /// Pins the behaviour expressed by the test name: format check multiple quotes. [Test] public void FormatCheckMultipleQuotes() { @@ -438,6 +459,7 @@ public void FormatCheckMultipleQuotes() } } + /// Pins the behaviour expressed by the test name: format check multiple double quotes. [Test] public void FormatCheckMultipleDoubleQuotes() { @@ -460,6 +482,7 @@ public void FormatCheckMultipleDoubleQuotes() } } + /// Pins the behaviour expressed by the test name: format check multiple pipe. [Test] public void FormatCheckMultiplePipe() { @@ -483,6 +506,7 @@ public void FormatCheckMultiplePipe() } + /// Pins the behaviour expressed by the test name: format check multiple null. [Test] public void FormatCheckMultipleNull() { @@ -505,6 +529,7 @@ public void FormatCheckMultipleNull() } } + /// Pins the behaviour expressed by the test name: format check multiple empty. [Test] public void FormatCheckMultipleEmpty() { @@ -528,6 +553,7 @@ public void FormatCheckMultipleEmpty() } + /// Pins the behaviour expressed by the test name: format check multiple empty null. [Test] public void FormatCheckMultipleEmptyNull() { @@ -550,6 +576,7 @@ public void FormatCheckMultipleEmptyNull() } } + /// Pins the behaviour expressed by the test name: format check multiple empty all. [Test] public void FormatCheckMultipleEmptyAll() { @@ -573,6 +600,7 @@ public void FormatCheckMultipleEmptyAll() } + /// Pins the behaviour expressed by the test name: format check multiple reset triggered. [Test] public void FormatCheckMultipleResetTriggered() { From dfcc15717ecb6286dab9507cf1a0b3367bd85ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:40:27 +0200 Subject: [PATCH 16/29] docs(compliance-tests): author XML doc comments on test surface --- ...ConfigurationPolymorphicXsdValidationTests.cs | 16 ++++++++++++++++ .../DevicesEnvelopeShapeXsdValidationTests.cs | 3 +++ .../L1_XsdValidation/SchemaLoadTests.cs | 5 +++++ .../Xsd11FeaturePresenceTests.cs | 6 ++++++ .../CppAgentJsonV2ProbeEnvelopeShapeTests.cs | 5 +++++ .../L2_CrossImpl/CppAgentParityWorkflowTests.cs | 11 +++++++++++ .../JsonMqttProbeEnvelopeE2ETests.cs | 7 +++++++ 7 files changed, 53 insertions(+) diff --git a/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/ConfigurationPolymorphicXsdValidationTests.cs b/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/ConfigurationPolymorphicXsdValidationTests.cs index d2a002d02..f54f1fd16 100644 --- a/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/ConfigurationPolymorphicXsdValidationTests.cs +++ b/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/ConfigurationPolymorphicXsdValidationTests.cs @@ -137,6 +137,8 @@ private static readonly (string Name, string Body, string ContainerXp, string Le "//*[local-name()='SolidModel']", "ScaleDataSet", true, new[] { "Y" }, XyzAlphabet, null), }; + /// Runs the all combinations operation. + /// The result of the operation. public static IEnumerable AllCombinations() { foreach (var version in Versions) @@ -149,6 +151,16 @@ public static IEnumerable AllCombinations() } } + /// Pins the behaviour expressed by the test name: configuration polymorphism combination emits well formed xml. + /// The version. + /// The combo name. + /// The body. + /// The container xp. + /// The leaf name. + /// The is data set. + /// The expected keys. + /// The spec alphabet. + /// The expected text value. [TestCaseSource(nameof(AllCombinations))] public void Configuration_polymorphism_combination_emits_well_formed_xml( string version, @@ -237,6 +249,10 @@ public void Configuration_polymorphism_combination_emits_well_formed_xml( // form and the DataSet form of the same polymorphism leaf — the XSD's // constraint forbids it. Pinning structurally so a future // wire-format regression that emits both is caught here. + /// Pins the behaviour expressed by the test name: configuration polymorphism choice forbids both forms in the same container. + /// The simple leaf name. + /// The data set leaf name. + /// The body. [TestCase("Origin", "OriginDataSet", "1 2 31", TestName = "CoordinateSystem cannot carry both Origin and OriginDataSet")] [TestCase("Axis", "AxisDataSet", "1 2 31", diff --git a/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/DevicesEnvelopeShapeXsdValidationTests.cs b/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/DevicesEnvelopeShapeXsdValidationTests.cs index cda6c5c08..fb789ea11 100644 --- a/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/DevicesEnvelopeShapeXsdValidationTests.cs +++ b/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/DevicesEnvelopeShapeXsdValidationTests.cs @@ -28,6 +28,7 @@ namespace MTConnect.Compliance.Tests.L1_XsdValidation // - MTConnect v2.7 XSD MTConnectDevices_2.7.xsd lines 5029-5051 // (DevicesType complex type). // - W3C XML 1.0 §2.3 (Names are case-sensitive). + /// Pins the behaviour expressed by the test name: devices envelope shape xsd validation tests. [TestFixture] [Category("CppAgentJsonV2Envelope")] public class DevicesEnvelopeShapeXsdValidationTests @@ -60,6 +61,7 @@ private static IDevicesResponseDocument BuildMultiDeviceDocument() } + /// Pins the behaviour expressed by the test name: probe envelope has agent and device under devices per v2 7 devices type. [Test] public void Probe_envelope_has_Agent_and_Device_under_Devices_per_v2_7_DevicesType() { @@ -96,6 +98,7 @@ public void Probe_envelope_has_Agent_and_Device_under_Devices_per_v2_7_DevicesTy } + /// Pins the behaviour expressed by the test name: agent name attribute is case sensitive per w3 c x m l 1 0 section 2 3. [Test] public void Agent_name_attribute_is_case_sensitive_per_W3C_XML_1_0_section_2_3() { diff --git a/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/SchemaLoadTests.cs b/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/SchemaLoadTests.cs index 18f6915e5..fdc26c5e2 100644 --- a/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/SchemaLoadTests.cs +++ b/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/SchemaLoadTests.cs @@ -43,6 +43,7 @@ namespace MTConnect.Compliance.Tests.L1_XsdValidation // Source for the embedded W3C XSDs: // https://www.w3.org/1999/xlink.xsd // https://www.w3.org/2001/xml.xsd + /// Pins the behaviour expressed by the test name: schema load tests. [TestFixture] public class SchemaLoadTests { @@ -102,6 +103,8 @@ public class SchemaLoadTests "v2_7/MTConnectDevices_2.7.xsd" }; + /// Runs the all schemas operation. + /// The result of the operation. public static IEnumerable AllSchemas() { var asm = typeof(SchemaLoadTests).Assembly; @@ -154,6 +157,8 @@ private static string ToDisplayPath(string resourceName) return rest.Substring(0, firstDot) + "/" + rest.Substring(firstDot + 1); } + /// Pins the behaviour expressed by the test name: schema loads without errors. + /// The resource name. [TestCaseSource(nameof(AllSchemas))] public void Schema_loads_without_errors(string resourceName) { diff --git a/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/Xsd11FeaturePresenceTests.cs b/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/Xsd11FeaturePresenceTests.cs index 2f003b4dd..ad4d75f16 100644 --- a/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/Xsd11FeaturePresenceTests.cs +++ b/tests/Compliance/MTConnect-Compliance-Tests/L1_XsdValidation/Xsd11FeaturePresenceTests.cs @@ -52,6 +52,8 @@ public class Xsd11FeaturePresenceTests private const string XsdNamespace = "http://www.w3.org/2001/XMLSchema"; private const string ResourcePrefix = "MTConnect.Compliance.Tests.Schemas."; + /// Runs the xsd11 blocked display paths operation. + /// The result of the operation. public static IEnumerable Xsd11BlockedDisplayPaths() { // Drive the parametrisation off SchemaLoadTests.Xsd11BlockedSchemas @@ -71,6 +73,8 @@ public static IEnumerable Xsd11BlockedDisplayPaths() // + maxOccurs > 1; Error: xs:any inside xs:all) without per-family // case-pinning that would fragility-couple to upstream's editing // style. + /// Pins the behaviour expressed by the test name: schema carries at least one xsd 1 1 feature. + /// The display path. [TestCaseSource(nameof(Xsd11BlockedDisplayPaths))] public void Schema_carries_at_least_one_xsd_1_1_feature(string displayPath) { @@ -121,6 +125,7 @@ public void Schema_carries_at_least_one_xsd_1_1_feature(string displayPath) // them, this test will fail and the preprocessor's handling can // be exercised end-to-end (the preprocessor already strips both; // the test surfaces that the schemas now exercise the path). + /// Pins the behaviour expressed by the test name: no schema carries xs assert or xs override yet. [Test] public void No_schema_carries_xs_assert_or_xs_override_yet() { @@ -152,6 +157,7 @@ public void No_schema_carries_xs_assert_or_xs_override_yet() // namespace". A future WG-side change to '##other' or to a // literal URI list is structurally fine but worth pinning so a // typo (e.g. '#targetNamespace') surfaces here. + /// Pins the behaviour expressed by the test name: not namespace attribute value is target namespace token. [Test] public void notNamespace_attribute_value_is_targetNamespace_token() { diff --git a/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentJsonV2ProbeEnvelopeShapeTests.cs b/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentJsonV2ProbeEnvelopeShapeTests.cs index 8d601b4af..d5ea0f917 100644 --- a/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentJsonV2ProbeEnvelopeShapeTests.cs +++ b/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentJsonV2ProbeEnvelopeShapeTests.cs @@ -41,6 +41,7 @@ namespace MTConnect.Compliance.Tests.L2_CrossImpl // emitted JSON's structural shape matches a frozen reference. The // Docker-bound full cross-impl parity workflow lives in // CppAgentParityWorkflowTests (Category=RequiresDocker,E2E). + /// Pins the behaviour expressed by the test name: cpp agent json v2 probe envelope shape tests. [TestFixture] [Category("CppAgentJsonV2Envelope")] public class CppAgentJsonV2ProbeEnvelopeShapeTests @@ -82,6 +83,7 @@ private static JsonElement Emit(IDevicesResponseDocument document) } + /// Pins the behaviour expressed by the test name: probe envelope matches cppagent j s o n v2 keyed object shape. [Test] public void Probe_envelope_matches_cppagent_JSON_v2_keyed_object_shape() { @@ -126,6 +128,7 @@ public void Probe_envelope_matches_cppagent_JSON_v2_keyed_object_shape() } + /// Pins the behaviour expressed by the test name: probe envelope agent element under devices matches x s d v2 7 devices type. [Test] public void Probe_envelope_Agent_element_under_Devices_matches_XSD_v2_7_DevicesType() { @@ -156,6 +159,7 @@ public void Probe_envelope_Agent_element_under_Devices_matches_XSD_v2_7_DevicesT } + /// Pins the behaviour expressed by the test name: probe envelope agent name preserves case per w3 c x m l 1 0 section 2 3. [Test] public void Probe_envelope_Agent_name_preserves_case_per_W3C_XML_1_0_section_2_3() { @@ -183,6 +187,7 @@ public void Probe_envelope_Agent_name_preserves_case_per_W3C_XML_1_0_section_2_3 } + /// Pins the behaviour expressed by the test name: probe envelope round trip through named formatter matches emitted shape. [Test] public void Probe_envelope_round_trip_through_named_formatter_matches_emitted_shape() { diff --git a/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentParityWorkflowTests.cs b/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentParityWorkflowTests.cs index eb4aa61a3..591cc604a 100644 --- a/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentParityWorkflowTests.cs +++ b/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentParityWorkflowTests.cs @@ -40,6 +40,7 @@ namespace MTConnect.Compliance.Tests.L2_CrossImpl // to match. // - https://schemas.mtconnect.org/schemas/MTConnectDevices_2.5.xsd // and MTConnectStreams_2.5.xsd — the shape both agents emit. + /// Pins the behaviour expressed by the test name: cpp agent parity workflow tests. [TestFixture] [Category("RequiresDocker")] [Category("E2E")] @@ -62,6 +63,8 @@ public class CppAgentParityWorkflowTests private string? _stagingDir; private Whitelist? _whitelist; + /// Sets up the fixture before each test. + /// The result of the operation. [OneTimeSetUp] public async Task GlobalSetUp() { @@ -177,6 +180,8 @@ public async Task GlobalSetUp() } } + /// Tears down the fixture after each test. + /// The result of the operation. [OneTimeTearDown] public async Task GlobalTearDown() { @@ -195,18 +200,24 @@ public async Task GlobalTearDown() } } + /// Pins the behaviour expressed by the test name: probe envelope byte diff is empty modulo whitelist. + /// The result of the operation. [Test] public async Task Probe_envelope_byte_diff_is_empty_modulo_whitelist() { await CompareEnvelopes("/probe", "MTConnectDevices").ConfigureAwait(false); } + /// Pins the behaviour expressed by the test name: current envelope byte diff is empty modulo whitelist. + /// The result of the operation. [Test] public async Task Current_envelope_byte_diff_is_empty_modulo_whitelist() { await CompareEnvelopes("/current", "MTConnectStreams").ConfigureAwait(false); } + /// Pins the behaviour expressed by the test name: sample envelope byte diff is empty modulo whitelist. + /// The result of the operation. [Test] public async Task Sample_envelope_byte_diff_is_empty_modulo_whitelist() { diff --git a/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/JsonMqttProbeEnvelopeE2ETests.cs b/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/JsonMqttProbeEnvelopeE2ETests.cs index a18c80a94..c818177f5 100644 --- a/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/JsonMqttProbeEnvelopeE2ETests.cs +++ b/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/JsonMqttProbeEnvelopeE2ETests.cs @@ -48,6 +48,7 @@ namespace MTConnect.Compliance.Tests.L2_CrossImpl // Protocol" — Probe topic structure and payload semantics. // - https://github.com/mtconnect/cppagent — reference encoder whose // JSON v2 shape the .NET formatter mirrors. + /// Pins the behaviour expressed by the test name: json mqtt probe envelope e2 e tests. [TestFixture] [Category("RequiresDocker")] [Category("E2E")] @@ -72,6 +73,8 @@ public class JsonMqttProbeEnvelopeE2ETests private object? _module; private MethodInfo? _stopMethod; + /// Sets up the fixture before each test. + /// The result of the operation. [OneTimeSetUp] public async Task GlobalSetUp() { @@ -131,6 +134,8 @@ public async Task GlobalSetUp() startMethod.Invoke(_module, new object[] { true }); } + /// Tears down the fixture after each test. + /// The result of the operation. [OneTimeTearDown] public async Task GlobalTearDown() { @@ -148,6 +153,8 @@ public async Task GlobalTearDown() } + /// Pins the behaviour expressed by the test name: e2 e multi device probe envelope round trip through real broker. + /// The result of the operation. [Test] public async Task E2E_multi_device_Probe_envelope_round_trip_through_real_broker() { From 5c3c83084d145ac0a78e535c291eb70b02b76074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:41:56 +0200 Subject: [PATCH 17/29] docs(tests-agents): author XML doc comments on test surface --- .../MTConnect.NET-Tests-Agents/AgentRunner.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/MTConnect.NET-Tests-Agents/AgentRunner.cs b/tests/MTConnect.NET-Tests-Agents/AgentRunner.cs index c3dedb956..e2776c1d1 100644 --- a/tests/MTConnect.NET-Tests-Agents/AgentRunner.cs +++ b/tests/MTConnect.NET-Tests-Agents/AgentRunner.cs @@ -11,6 +11,7 @@ namespace MTConnect.Tests.Agents { + /// Represents the agent runner. public class AgentRunner : IDisposable { // Generous, CI-safe bounds. The embedded HTTP server's Start() is @@ -27,20 +28,32 @@ public class AgentRunner : IDisposable private readonly string _hostname; private readonly int _port; + /// Gets or sets the agent. public MTConnectAgentBroker Agent => _agent; + /// Gets or sets the http server. public MTConnectHttpServer HttpServer => _httpServer; + /// Gets or sets the devices. public IEnumerable Devices => _devices; + /// Gets or sets the hostname. public string Hostname => _hostname; + /// Gets or sets the port. public int Port => _port; + /// Initialises a new instance of the agent runner type. + /// The port. + /// The mtconnect version. public AgentRunner(int port, Version? mtconnectVersion = null) : this(IPAddress.Loopback.ToString(), port, mtconnectVersion) { } + /// Initialises a new instance of the agent runner type. + /// The hostname. + /// The port. + /// The mtconnect version. public AgentRunner(string hostname, int port = 5000, Version? mtconnectVersion = null) { _hostname = hostname; @@ -82,6 +95,8 @@ public AgentRunner(string hostname, int port = 5000, Version? mtconnectVersion = // Picks a TCP port the OS confirms is free, so concurrently // constructed fixtures never collide on a hard-coded port. + /// Runs the get free port operation. + /// The result of the operation. public static int GetFreePort() { var listener = new TcpListener(IPAddress.Loopback, 0); @@ -96,6 +111,7 @@ public static int GetFreePort() } } + /// Runs the start operation. public void Start() { _agent.Start(); @@ -107,6 +123,7 @@ public void Start() // CI-safe bound elapses. Polling the actual endpoint proves end to end // that the listener is bound and the agent is serving, removing the // start-up race that otherwise lets a client's first request fail. + /// Runs the wait for ready operation. public void WaitForReady() { var deadline = DateTime.UtcNow.AddMilliseconds(ServerReadyTimeoutMs); @@ -138,6 +155,7 @@ public void WaitForReady() + (lastError != null ? $" (last error: {lastError.Message})." : ".")); } + /// Runs the stop operation. public void Stop() { _agent.Stop(); @@ -172,6 +190,7 @@ private static void WaitForPortReleased(int port) } } + /// Runs the dispose operation. public void Dispose() { _httpServer.Dispose(); From b79e4e26c582ef7f9ede355215e8af11c716b6b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:43:22 +0200 Subject: [PATCH 18/29] docs(http-tests): author XML doc comments on test surface --- tests/MTConnect.NET-HTTP-Tests/Clients/Current.cs | 6 ++++++ .../Clients/HttpClientFixture.cs | 9 +++++++++ tests/MTConnect.NET-HTTP-Tests/Clients/Probe.cs | 5 +++++ tests/MTConnect.NET-HTTP-Tests/Clients/Sample.cs | 6 ++++++ tests/MTConnect.NET-HTTP-Tests/Clients/SampleStream.cs | 4 ++++ 5 files changed, 30 insertions(+) diff --git a/tests/MTConnect.NET-HTTP-Tests/Clients/Current.cs b/tests/MTConnect.NET-HTTP-Tests/Clients/Current.cs index baee664e4..eb7874b23 100644 --- a/tests/MTConnect.NET-HTTP-Tests/Clients/Current.cs +++ b/tests/MTConnect.NET-HTTP-Tests/Clients/Current.cs @@ -11,9 +11,11 @@ namespace MTConnect.Tests.Http.Clients // MTConnectHttpServer started by AgentRunner, exercising the HTTP current // request/response path end to end for XML and JSON, all devices, a single // device and a device path filter. + /// Pins the behaviour expressed by the test name: current. [TestFixture] public class Current : HttpClientFixture { + /// Pins the behaviour expressed by the test name: run xml. [Test] public void RunXml() { @@ -25,6 +27,7 @@ public void RunXml() Assert.That(response.Streams.Count(), Is.EqualTo(ExpectedDocumentEntryCount), "XML Current did not return all device streams"); } + /// Pins the behaviour expressed by the test name: run json. [Test] public void RunJson() { @@ -36,6 +39,7 @@ public void RunJson() Assert.That(response.Streams.Count(), Is.EqualTo(ExpectedDocumentEntryCount), "JSON Current did not return all device streams"); } + /// Pins the behaviour expressed by the test name: run device xml. [Test] public void RunDeviceXml() { @@ -47,6 +51,7 @@ public void RunDeviceXml() Assert.That(response.Streams.FirstOrDefault(o => o.Name == DeviceName), Is.Not.Null, $"XML Current did not return device {DeviceName}"); } + /// Pins the behaviour expressed by the test name: run device json. [Test] public void RunDeviceJson() { @@ -58,6 +63,7 @@ public void RunDeviceJson() Assert.That(response.Streams.FirstOrDefault(o => o.Name == DeviceName), Is.Not.Null, $"JSON Current did not return device {DeviceName}"); } + /// Pins the behaviour expressed by the test name: run device path xml. [Test] public void RunDevicePathXml() { diff --git a/tests/MTConnect.NET-HTTP-Tests/Clients/HttpClientFixture.cs b/tests/MTConnect.NET-HTTP-Tests/Clients/HttpClientFixture.cs index 18aad3120..babe7478c 100644 --- a/tests/MTConnect.NET-HTTP-Tests/Clients/HttpClientFixture.cs +++ b/tests/MTConnect.NET-HTTP-Tests/Clients/HttpClientFixture.cs @@ -15,22 +15,30 @@ namespace MTConnect.Tests.Http.Clients // per fixture removes that contention. AgentRunner.Start() blocks until the // server actually answers a Probe, so the first client request never races // the fire-and-forget socket bind. + /// Represents the http client fixture. public abstract class HttpClientFixture { + /// The hostname. protected const string Hostname = "127.0.0.1"; + /// The device name. protected const string DeviceName = "OKUMA-Lathe"; + /// The device uuid. protected const string DeviceUuid = "OKUMA.Lathe.123456"; + /// Gets or sets the agent runner. protected AgentRunner AgentRunner { get; private set; } = null!; + /// Gets or sets the port. protected int Port { get; private set; } // Streams/devices include the implicit Agent device alongside the two // device files AgentRunner loads, so a full document carries one more // entry than AgentRunner.Devices. + /// Gets or sets the expected document entry count. protected int ExpectedDocumentEntryCount => AgentRunner.Devices.Count() + 1; + /// Sets up the fixture before each test. [OneTimeSetUp] public void OneTimeSetUp() { @@ -39,6 +47,7 @@ public void OneTimeSetUp() AgentRunner.Start(); } + /// Tears down the fixture after each test. [OneTimeTearDown] public void OneTimeTearDown() { diff --git a/tests/MTConnect.NET-HTTP-Tests/Clients/Probe.cs b/tests/MTConnect.NET-HTTP-Tests/Clients/Probe.cs index 101998332..5b5ec2278 100644 --- a/tests/MTConnect.NET-HTTP-Tests/Clients/Probe.cs +++ b/tests/MTConnect.NET-HTTP-Tests/Clients/Probe.cs @@ -11,9 +11,11 @@ namespace MTConnect.Tests.Http.Clients // MTConnectHttpServer started by AgentRunner, exercising the HTTP probe // request/response path end to end for XML and JSON, all devices and a // single device. + /// Pins the behaviour expressed by the test name: probe. [TestFixture] public class Probe : HttpClientFixture { + /// Pins the behaviour expressed by the test name: run xml. [Test] public void RunXml() { @@ -25,6 +27,7 @@ public void RunXml() Assert.That(response.Devices.Count(), Is.EqualTo(ExpectedDocumentEntryCount), "XML Probe did not return all devices"); } + /// Pins the behaviour expressed by the test name: run json. [Test] public void RunJson() { @@ -36,6 +39,7 @@ public void RunJson() Assert.That(response.Devices.Count(), Is.EqualTo(ExpectedDocumentEntryCount), "JSON Probe did not return all devices"); } + /// Pins the behaviour expressed by the test name: run device xml. [Test] public void RunDeviceXml() { @@ -47,6 +51,7 @@ public void RunDeviceXml() Assert.That(response.Devices.FirstOrDefault(o => o.Name == DeviceName), Is.Not.Null, $"XML Probe did not return device {DeviceName}"); } + /// Pins the behaviour expressed by the test name: run device json. [Test] public void RunDeviceJson() { diff --git a/tests/MTConnect.NET-HTTP-Tests/Clients/Sample.cs b/tests/MTConnect.NET-HTTP-Tests/Clients/Sample.cs index 5d1f7e36c..5d96b61aa 100644 --- a/tests/MTConnect.NET-HTTP-Tests/Clients/Sample.cs +++ b/tests/MTConnect.NET-HTTP-Tests/Clients/Sample.cs @@ -11,9 +11,11 @@ namespace MTConnect.Tests.Http.Clients // MTConnectHttpServer started by AgentRunner, exercising the HTTP sample // request/response path end to end for XML and JSON, all devices, a single // device and a device path filter. + /// Pins the behaviour expressed by the test name: sample. [TestFixture] public class Sample : HttpClientFixture { + /// Pins the behaviour expressed by the test name: run xml. [Test] public void RunXml() { @@ -25,6 +27,7 @@ public void RunXml() Assert.That(response.Streams.Count(), Is.EqualTo(ExpectedDocumentEntryCount), "XML Sample did not return all device streams"); } + /// Pins the behaviour expressed by the test name: run json. [Test] public void RunJson() { @@ -36,6 +39,7 @@ public void RunJson() Assert.That(response.Streams.Count(), Is.EqualTo(ExpectedDocumentEntryCount), "JSON Sample did not return all device streams"); } + /// Pins the behaviour expressed by the test name: run device xml. [Test] public void RunDeviceXml() { @@ -47,6 +51,7 @@ public void RunDeviceXml() Assert.That(response.Streams.FirstOrDefault(o => o.Name == DeviceName), Is.Not.Null, $"XML Sample did not return device {DeviceName}"); } + /// Pins the behaviour expressed by the test name: run device json. [Test] public void RunDeviceJson() { @@ -58,6 +63,7 @@ public void RunDeviceJson() Assert.That(response.Streams.FirstOrDefault(o => o.Name == DeviceName), Is.Not.Null, $"JSON Sample did not return device {DeviceName}"); } + /// Pins the behaviour expressed by the test name: run device path xml. [Test] public void RunDevicePathXml() { diff --git a/tests/MTConnect.NET-HTTP-Tests/Clients/SampleStream.cs b/tests/MTConnect.NET-HTTP-Tests/Clients/SampleStream.cs index 678eb05da..2a5b3783f 100644 --- a/tests/MTConnect.NET-HTTP-Tests/Clients/SampleStream.cs +++ b/tests/MTConnect.NET-HTTP-Tests/Clients/SampleStream.cs @@ -20,6 +20,7 @@ namespace MTConnect.Tests.Http.Clients // asserts the streamed Sample delivers that observation back. This // exercises the broker ingest/sequence/buffer path and the HTTP server // stream + HTTP streaming-client per-chunk loop end to end. + /// Pins the behaviour expressed by the test name: sample client. [TestFixture] public class SampleClient { @@ -37,6 +38,7 @@ public class SampleClient private readonly object _lock = new object(); + /// Sets up the fixture before each test. [OneTimeSetUp] public void OneTimeSetUp() { @@ -50,6 +52,7 @@ public void OneTimeSetUp() _client.Start(); } + /// Tears down the fixture after each test. [OneTimeTearDown] public void OneTimeTearDown() { @@ -88,6 +91,7 @@ private void SampleReceived(object? sender, IStreamsResponseDocument response) } + /// Pins the behaviour expressed by the test name: run. [Test] public void Run() { From 340c85e66b93b80a44dbc7c7e798db3108087ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 12:44:03 +0200 Subject: [PATCH 19/29] docs(docs-tests): author XML doc comments on test surface --- .../DocsReferenceGenerationTests.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/MTConnect.NET-Docs-Tests/DocsReferenceGenerationTests.cs b/tests/MTConnect.NET-Docs-Tests/DocsReferenceGenerationTests.cs index 9076fc030..922a42391 100644 --- a/tests/MTConnect.NET-Docs-Tests/DocsReferenceGenerationTests.cs +++ b/tests/MTConnect.NET-Docs-Tests/DocsReferenceGenerationTests.cs @@ -46,6 +46,7 @@ private static string RepoRoot } } + /// Pins the behaviour expressed by the test name: http api page is in sync with source. [Test] public void HttpApi_Page_Is_In_Sync_With_Source() { @@ -63,6 +64,7 @@ public void HttpApi_Page_Is_In_Sync_With_Source() } } + /// Pins the behaviour expressed by the test name: environment variables page is in sync with source. [Test] public void EnvironmentVariables_Page_Is_In_Sync_With_Source() { @@ -79,6 +81,7 @@ public void EnvironmentVariables_Page_Is_In_Sync_With_Source() } } + /// Pins the behaviour expressed by the test name: configuration page is in sync with source. [Test] public void Configuration_Page_Is_In_Sync_With_Source() { @@ -96,6 +99,7 @@ public void Configuration_Page_Is_In_Sync_With_Source() } } + /// Pins the behaviour expressed by the test name: cli page is in sync with source. [Test] public void Cli_Page_Is_In_Sync_With_Source() { @@ -120,6 +124,7 @@ public void Cli_Page_Is_In_Sync_With_Source() } } + /// Pins the behaviour expressed by the test name: endpoint code has no stale entries in markdown. [Test] public void Endpoint_Code_Has_No_Stale_Entries_In_Markdown() { @@ -150,6 +155,7 @@ public void Endpoint_Code_Has_No_Stale_Entries_In_Markdown() } } + /// Pins the behaviour expressed by the test name: index page is in sync. [Test] public void Index_Page_Is_In_Sync() { From 8b5e1bc6e91fc0584bbaac4e70054cc11f3e6881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Mon, 1 Jun 2026 15:27:28 +0200 Subject: [PATCH 20/29] build(agent-processor): pin ConfigurationManager for docfx resolution --- .../MTConnect.NET-AgentProcessor-Python.csproj | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/agent/Processors/MTConnect.NET-AgentProcessor-Python/MTConnect.NET-AgentProcessor-Python.csproj b/agent/Processors/MTConnect.NET-AgentProcessor-Python/MTConnect.NET-AgentProcessor-Python.csproj index 7d942b3e8..8e354f0b4 100644 --- a/agent/Processors/MTConnect.NET-AgentProcessor-Python/MTConnect.NET-AgentProcessor-Python.csproj +++ b/agent/Processors/MTConnect.NET-AgentProcessor-Python/MTConnect.NET-AgentProcessor-Python.csproj @@ -41,6 +41,17 @@ all + + From 8f0795cde9fdbb872f5be181e4a924c9bf7ece42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Tue, 2 Jun 2026 16:43:11 +0200 Subject: [PATCH 21/29] docs(reference): regenerate env-vars page for shifted source line The doc-comments commit on MTConnect-Compliance-Tests shifted the line of the FixtureDirEnv read in CppAgentParityWorkflowTests.cs from 488 to 499. The generated page embeds source line numbers, so the change desynced docs/reference/environment-variables.md and the in-sync test in MTConnect.NET-Docs-Tests failed on every integration branch layered on top of this PR (#185, #186). --- docs/reference/environment-variables.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/environment-variables.md b/docs/reference/environment-variables.md index 37d67c6c4..1953b7049 100644 --- a/docs/reference/environment-variables.md +++ b/docs/reference/environment-variables.md @@ -84,7 +84,7 @@ Every environment-variable reference discovered in the source tree. Both the C# | Kind | Source | Default / value | Context | | --- | --- | --- | --- | -| `csharp-read` | [`tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentParityWorkflowTests.cs:488`](https://github.com/TrakHound/MTConnect.NET/blob/master/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentParityWorkflowTests.cs#L488) | | = Environment.GetEnvironmentVariable(FixtureDirEnv) | +| `csharp-read` | [`tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentParityWorkflowTests.cs:499`](https://github.com/TrakHound/MTConnect.NET/blob/master/tests/Compliance/MTConnect-Compliance-Tests/L2_CrossImpl/CppAgentParityWorkflowTests.cs#L499) | | = Environment.GetEnvironmentVariable(FixtureDirEnv) | Adding a new `Environment.GetEnvironmentVariable("…")` call, a new `${MTCONNECT_…}` read in a contributor script, or a new `$env:MTCONNECT_…` reference in a PowerShell script without regenerating this page fails the validation test in CI. From 60328394dae5ec384eed99f8797d6776d68bfe6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Tue, 2 Jun 2026 17:58:58 +0200 Subject: [PATCH 22/29] fix(docs-gen): escape bare < in generated API markdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docfx emits two C#-generic patterns whose opening `<` is bare while the closing `>` is markdown-escaped as `\>`: 1. heading text after the anchor close, e.g. `### CollectShell(string, List)` 2. return / parameter blocks where docfx renders an outer-generic link followed by an inner-generic link, e.g. ` [List](…)<[EnvVarInfo](…)\>` VitePress's underlying Vue template compiler sees the bare `<` as the start tag of an element that never closes (the escaped `\>` is rendered as a literal `>` rather than an end-tag token), tripping "Element is missing end tag" during `vitepress build` and failing the Docs-site CI's Build VitePress site job. Add a post-processing awk pass to generate-api-ref.sh that rewrites `<[A-Z]` and `<[` outside fenced code blocks to `<[A-Z]` / `<[`. The `<` HTML entity survives the markdown -> HTML pipeline, whereas a backslash-escape would decode back to `<` and re-trip the same error. The awk filter tracks ```-fence state so signatures in code blocks (e.g. `public IReadOnlyList Collect(...)`) stay untouched, and the lowercase `` anchor itself is unaffected because the pattern requires either an uppercase letter or `[`. --- docs/scripts/generate-api-ref.sh | 44 ++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/scripts/generate-api-ref.sh b/docs/scripts/generate-api-ref.sh index 7567af503..ea8c714b0 100755 --- a/docs/scripts/generate-api-ref.sh +++ b/docs/scripts/generate-api-ref.sh @@ -149,4 +149,48 @@ find docs/api -mindepth 1 -maxdepth 1 -not -name 'index.md' -exec rm -rf {} + find docs/api -name '*.md' -not -name 'index.md' -print0 \ | xargs -0 sed -i -E 's#]*)?>##g' +# docfx emits two C#-generic patterns whose opening `<` is bare while +# the closing `>` is markdown-escaped as `\>`. Vue's template compiler +# then treats the bare `<` as the start tag of an element that never +# closes (the escaped `\>` is rendered as a literal `>` in HTML, not +# as an end-tag token), tripping "Element is missing end tag" at +# vitepress build time. The two patterns are: +# +# 1. Heading text after the anchor close, e.g. +# `### Collect\(string, List\)`. +# 2. Return / parameter blocks where docfx renders an outer-generic +# link followed by an inner-generic link, e.g. +# ` [List](url-of-list)<[EnvVarInfo](url-of-envvarinfo)\>`. +# +# Both forms feed the parser a `<` followed by either an uppercase +# letter (heading-text type name) or a `[` (markdown link opener) and +# never close it with a real ``. Rewrite both bare opens as +# `<` HTML entities so the markdown -> HTML pipeline can't re-emit +# a literal `<` (a backslash-escape would survive markdown but the +# Vue template parser sees the rendered HTML, where `\<` decodes to +# `<` again and re-trips the same error). The `` anchor +# itself is intentionally not touched -- `a` is lowercase, so the +# `<[A-Z]` alternative misses it, and the `<\[` alternative is +# unambiguous. Fenced code blocks render via the highlighter, not +# Vue's template parser, so the bare generics they contain (e.g. +# `public IReadOnlyList Collect(...)`) do not need +# escaping. A small awk pass tracks ```-fence state and skips lines +# inside fences so code-block content stays untouched. +while IFS= read -r -d '' md_file; do + awk ' + BEGIN { in_fence = 0 } + /^```/ { in_fence = !in_fence; print; next } + in_fence { print; next } + { + # Replace ` "${md_file}.tmp" && mv "${md_file}.tmp" "${md_file}" +done < <(find docs/api -name '*.md' -not -name 'index.md' -print0) + echo "==> done. $(find docs/api -name '*.md' -not -name 'index.md' | wc -l) pages generated." From a84b5e92fe8d7ca7e5c3757b7b28e6dd98768eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Tue, 2 Jun 2026 18:44:56 +0200 Subject: [PATCH 23/29] docs(pallet-tests): keep multi-line on one line for docfx The class-level XML doc comment on PalletMeasurementContractTests wrapped a single `PhysicalAsset > Pallet > Measurements` span across two source lines: /// Per the MTConnect SysML model, the PhysicalAsset > Pallet /// > Measurements package declares ... docfx flattens the wrapped XML doc into adjacent markdown lines, producing a line that starts with `> Measurements package declares ...`. The leading `> ` is then re-parsed as a markdown blockquote, eating the `` close tag and tripping Vue's "Element is missing end tag" error during the Docs-site CI's Build VitePress site job. Reflow the comment so the `...` span fits on one line. The generated markdown then carries the full code span on a single line and the blockquote-collision goes away. --- .../Assets/Pallet/PalletMeasurementContractTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs b/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs index e1ab3bbd2..715816fe5 100644 --- a/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Assets/Pallet/PalletMeasurementContractTests.cs @@ -15,8 +15,8 @@ namespace MTConnect.Tests.Common.Assets.Pallet /// scaffolding produced by the SysML measurement template, in /// parity with the long-standing CuttingTools measurement DTOs. /// - /// Per the MTConnect SysML model, the PhysicalAsset > Pallet - /// > Measurements package declares ten concrete measurement + /// Per the MTConnect SysML model, the PhysicalAsset > Pallet > Measurements + /// package declares ten concrete measurement /// subclasses (Weight, Height, Width, Length, Swing plus their /// Loaded* counterparts) that generalize from an abstract /// Measurement base. The C# generator must emit each one From 62599d7e1237ce86a55420fa3bb9a5b76b268d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Tue, 2 Jun 2026 18:45:14 +0200 Subject: [PATCH 24/29] fix(docs-gen): escape {{ in generated API markdown prose docfx preserves verbatim spec-marker text from XML doc comments like "{{term(data set)}} of the number of {{termplural(Asset)}} ..." in the generated `*.md` files. VitePress's underlying Vue template compiler then treats `{{ ... }}` as a mustache interpolation and tries to parse the contents as a JavaScript expression. Spec markers contain unquoted spaces and operator-like tokens, so the parse fails and the Docs-site CI's Build VitePress site job aborts with errors like `Error parsing JavaScript expression: Unexpected token`. Extend the post-processing awk pass to rewrite every `{{` outside fenced code blocks as `{{`. The html-entity form survives the markdown -> HTML pipeline and presents the original characters to readers without engaging Vue's mustache parser. Standalone `}}` is harmless once its opening `{{` is gone, so it is left alone. --- docs/scripts/generate-api-ref.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/scripts/generate-api-ref.sh b/docs/scripts/generate-api-ref.sh index ea8c714b0..532cd2313 100755 --- a/docs/scripts/generate-api-ref.sh +++ b/docs/scripts/generate-api-ref.sh @@ -182,13 +182,22 @@ while IFS= read -r -d '' md_file; do /^```/ { in_fence = !in_fence; print; next } in_fence { print; next } { - # Replace ` HTML pipeline. + gsub(/\{\{/, "\\{\\{", line) + print line } ' "${md_file}" > "${md_file}.tmp" && mv "${md_file}.tmp" "${md_file}" done < <(find docs/api -name '*.md' -not -name 'index.md' -print0) From e45b30951fcd0759baa17a246dcb28f2215295a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Tue, 2 Jun 2026 19:28:46 +0200 Subject: [PATCH 25/29] fix(docs): drop internal DocsGen tool from docfx project list The in-tree DocsGen generator produces the docs/api/ tree at build time; it is not a public NuGet surface, so its own API reference does not need to ship. Its EnvVarInventory summary embeds a bulleted list whose items mix six-space indents with bare tags, which docfx forwards verbatim into Markdown. VitePress's Vue template parser then sees an inline code element opening inside what Markdown promotes to an indented code block, and rejects the page with "Element is missing end tag" at api/MTConnect.NET_DocsGen.EnvVarInventory.md:85. Removing the project from docs/.docfx/docfx.json and the parallel list in docs/scripts/generate-api-ref.sh skips both the problematic page and every other DocsGen-namespaced page (none are referenced from any sidebar or cross-link). Three earlier escape fixes f7290a15, dcc4cdb8, f1507496 patched related cases but could not handle this specific Markdown / Vue interaction without rewriting the source XML doc comment, which is the longer path. --- docs/.docfx/docfx.json | 1 - docs/scripts/generate-api-ref.sh | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/.docfx/docfx.json b/docs/.docfx/docfx.json index 230da036d..c196606e9 100644 --- a/docs/.docfx/docfx.json +++ b/docs/.docfx/docfx.json @@ -31,7 +31,6 @@ "adapter/Modules/MTConnect.NET-AdapterModule-MQTT/bin/Debug/net8.0/MTConnect.NET-AdapterModule-MQTT.dll", "adapter/Modules/MTConnect.NET-AdapterModule-SHDR/bin/Debug/net8.0/MTConnect.NET-AdapterModule-SHDR.dll", "build/MTConnect.NET-SysML-Import/bin/Debug/net8.0/MTConnect.NET-SysML-Import.dll", - "build/MTConnect.NET-DocsGen/bin/Debug/net8.0/MTConnect.NET-DocsGen.dll", "build/MTConnect.NET.Builder/bin/Debug/net8.0/MTConnect.NET.Builder.dll", "examples/MTConnect.NET-Agent-Embedded/bin/Debug/net8.0/MTConnect.NET-Agent-Embedded.dll", "examples/MTConnect.NET-Client-HTTP/bin/Debug/net8.0/MTConnect.NET-Client-HTTP.dll", diff --git a/docs/scripts/generate-api-ref.sh b/docs/scripts/generate-api-ref.sh index 532cd2313..fa9544ee1 100755 --- a/docs/scripts/generate-api-ref.sh +++ b/docs/scripts/generate-api-ref.sh @@ -67,7 +67,6 @@ projects=( "adapter/Modules/MTConnect.NET-AdapterModule-MQTT" "adapter/Modules/MTConnect.NET-AdapterModule-SHDR" "build/MTConnect.NET-SysML-Import" - "build/MTConnect.NET-DocsGen" "build/MTConnect.NET.Builder" "examples/MTConnect.NET-Agent-Embedded" "examples/MTConnect.NET-Client-HTTP" From 85e4803bbea2d2e2ebf4a246c4b74ceb7edf1ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Tue, 2 Jun 2026 19:41:45 +0200 Subject: [PATCH 26/29] fix(docs): filter out DocsGen namespace at docfx level Dropping MTConnect.NET-DocsGen from the docfx project list and the generator script was insufficient: MTConnect.NET-Docs-Tests references DocsGen as a project reference, so the build copies MTConnect.NET-DocsGen.dll and its XML doc file into the tests' bin/Debug/net8.0/ output. Docfx then re-discovers the DocsGen types via the copy-local'd assembly and re-emits MTConnect.NET_DocsGen.*.md pages -- including the EnvVarInventory page whose summary still trips VitePress's Vue template parser. Add an apiRules exclude in docs/.docfx/filter.yml that drops the namespace at metadata extraction time. The filter runs after assembly discovery, so it catches the namespace regardless of which DLL pulls it in. --- docs/.docfx/filter.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/.docfx/filter.yml b/docs/.docfx/filter.yml index 687afa355..2c8c4621a 100644 --- a/docs/.docfx/filter.yml +++ b/docs/.docfx/filter.yml @@ -2,6 +2,18 @@ apiRules: - exclude: uidRegex: ^Ceen($|\.) type: Namespace + # MTConnect.NET-DocsGen is the in-tree generator that produces the + # docs/api/ Markdown tree itself, not a shipped public surface. Its + # source DLL is intentionally absent from docfx.json, but the + # MTConnect.NET-Docs-Tests assembly references DocsGen, so its + # XML doc file (which embeds a six-space-indented bullet list of + # bare tags that VitePress's Vue template parser rejects as + # "Element is missing end tag") is copy-local'd alongside the tests + # DLL and re-discovered by docfx. Filter out the namespace as the + # last-mile guard. + - exclude: + uidRegex: ^MTConnect\.NET_DocsGen($|\.) + type: Namespace # The legacy JSON v1 codec and the cppagent v2 codec each ship a type # named JsonProcessFeed{r,R}ate inside MTConnect.Assets.Json.CuttingTools. # The two pages collide on case-insensitive output paths (and on From a1fcb58f6ed2e31922d97c3dd30d6a12709c43ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Tue, 2 Jun 2026 19:55:04 +0200 Subject: [PATCH 27/29] ci(docs): lift Node heap to 8 GB for VitePress build The flat 2 000-page API reference plus the unified server + client bundles push rollup past the GitHub Actions runner's default Node heap (~4 GB) during the markdown -> Vue transform, aborting the build with "Ineffective mark-compacts near heap limit" / exit 134 even when no individual page fails to parse. The runner has 16 GB of RAM, so 8 GB is comfortably within budget and matches the local bluefin verification that produces a clean rc=0. --- .github/workflows/docs.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 8e06cc274..f11737fcf 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -139,6 +139,15 @@ jobs: run: npx vitepress build env: DOCS_BASE: /MTConnect.NET/ + # The flat 2 000-page API reference plus the unified server + + # client bundles push rollup past the GitHub Actions runner's + # default Node heap (~4 GB) during the markdown -> Vue + # transform. The previous symptom was 'Ineffective + # mark-compacts near heap limit' aborting the build with + # exit 134 even though no page actually fails to parse. Lift + # the cap to 8 GB -- runners have 16 GB of RAM, so this is + # well within budget. + NODE_OPTIONS: --max-old-space-size=8192 # Upload the built artifact only on the deploy path. PR builds stop # after the build step (success / failure surfaces in the check). From 4f1f6a6085300f301de16e7a8e3ff6a28ecd464e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Tue, 2 Jun 2026 20:02:39 +0200 Subject: [PATCH 28/29] fix(docs-gen): escape * inside spans in generated markdown docfx renders XML doc `*.sh` and `*.ps1` tags into `*.sh` / `*.ps1` markdown spans. When two such spans appear on the same line of the generated `*.md` -- as they do whenever an XML doc lists multiple glob patterns inline -- markdown-it interprets the four `*` characters as the bookends of two `` emphasis spans. The pre-existing `` open / close tags then end up spliced into the wrong positions in the rendered HTML, producing fragments like `.sh and ` with the element-nesting broken. Vue's template compiler then trips with `Element is missing end tag` during `vitepress build` and the Docs-site CI's Build VitePress site job aborts. Extend the post-processing awk pass to walk each `... ` span on a non-fenced line and rewrite every `*` inside to `*`. The html-entity preserves the visible character for readers while keeping markdown's emphasis parser from ever seeing a literal `*`. Single-span lines were never broken, but the same escape applies harmlessly to them too. --- docs/scripts/generate-api-ref.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/scripts/generate-api-ref.sh b/docs/scripts/generate-api-ref.sh index fa9544ee1..b17dc6494 100755 --- a/docs/scripts/generate-api-ref.sh +++ b/docs/scripts/generate-api-ref.sh @@ -196,7 +196,22 @@ while IFS= read -r -d '' md_file; do # JavaScript expression `term(data set)` and reject. The # html-entity form survives the markdown -> HTML pipeline. gsub(/\{\{/, "\\{\\{", line) - print line + # Escape `*` inside ... spans as `*`. + # Without this, two `*.sh` spans on a single line + # let markdown-it treat the `*` characters as the bookends of + # an `` span, producing `.sh and ` + # in the rendered HTML -- with the `` open/close braces + # spliced into broken positions -- which then trips Vue with + # "Element is missing end tag" during vitepress build. + out2 = ""; t = line + while (match(t, /]*)?>[^<]*<\/code>/)) { + prefix = substr(t, 1, RSTART - 1) + span = substr(t, RSTART, RLENGTH) + gsub(/\*/, "\\*", span) + out2 = out2 prefix span + t = substr(t, RSTART + RLENGTH) + } + print out2 t } ' "${md_file}" > "${md_file}.tmp" && mv "${md_file}.tmp" "${md_file}" done < <(find docs/api -name '*.md' -not -name 'index.md' -print0) From a115a3aa778094b562ed530f82e35131d4561e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Boly=C3=B3s?= Date: Tue, 2 Jun 2026 23:03:06 +0200 Subject: [PATCH 29/29] fix(docs): pin Node heap to 8 GB for the VitePress production build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 44-project docfx expansion generates ~2145 pages and the VitePress production build exceeds Node's default 4.2 GB heap, exiting 134 on ubuntu-latest. The Docs site workflow sets NODE_OPTIONS at the job level; the build-test-coverage workflow does not — so the RouteCheckTests OneTimeSetUp invocation of npm run build OOM-aborted there. Bake the heap setting into the npm script itself by invoking node --max-old-space-size=8192 against the vitepress bin. This avoids shell-prefix env syntax that would break on Windows, avoids adding cross-env as a dependency, and ensures every caller — workflow, test fixture, manual invocation — inherits the heap setting. --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 815605038..c87112d41 100644 --- a/docs/package.json +++ b/docs/package.json @@ -9,7 +9,7 @@ "predev": "npm run regen", "dev": "vitepress dev", "prebuild": "npm run regen", - "build": "vitepress build", + "build": "node --max-old-space-size=8192 node_modules/vitepress/bin/vitepress.js build", "preview": "vitepress preview", "check-links": "node scripts/check-broken-links.mjs ." },