diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 71ecdfd33..28057a043 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -7,6 +7,12 @@ "commands": [ "reportgenerator" ] + }, + "dotnet-stryker": { + "version": "4.16.0", + "commands": [ + "stryker" + ] } } } diff --git a/MTConnect.NET.sln b/MTConnect.NET.sln index 9bf4d7374..52f50daad 100644 --- a/MTConnect.NET.sln +++ b/MTConnect.NET.sln @@ -143,6 +143,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTConnect.NET-HTTP-Tests", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTConnect.NET-SysML-Tests", "tests\MTConnect.NET-SysML-Tests\MTConnect.NET-SysML-Tests.csproj", "{6CE969D2-A1E8-4BC1-85D8-303701B42F64}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTConnect.NET-Generator-Tests", "tests\MTConnect.NET-Generator-Tests\MTConnect.NET-Generator-Tests.csproj", "{8B61CE3B-DC8A-47CE-A34B-38BC57DFFD57}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -519,6 +521,14 @@ Global {6CE969D2-A1E8-4BC1-85D8-303701B42F64}.Package|Any CPU.Build.0 = Debug|Any CPU {6CE969D2-A1E8-4BC1-85D8-303701B42F64}.Release|Any CPU.ActiveCfg = Release|Any CPU {6CE969D2-A1E8-4BC1-85D8-303701B42F64}.Release|Any CPU.Build.0 = Release|Any CPU + {8B61CE3B-DC8A-47CE-A34B-38BC57DFFD57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8B61CE3B-DC8A-47CE-A34B-38BC57DFFD57}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B61CE3B-DC8A-47CE-A34B-38BC57DFFD57}.Docker|Any CPU.ActiveCfg = Debug|Any CPU + {8B61CE3B-DC8A-47CE-A34B-38BC57DFFD57}.Docker|Any CPU.Build.0 = Debug|Any CPU + {8B61CE3B-DC8A-47CE-A34B-38BC57DFFD57}.Package|Any CPU.ActiveCfg = Debug|Any CPU + {8B61CE3B-DC8A-47CE-A34B-38BC57DFFD57}.Package|Any CPU.Build.0 = Debug|Any CPU + {8B61CE3B-DC8A-47CE-A34B-38BC57DFFD57}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8B61CE3B-DC8A-47CE-A34B-38BC57DFFD57}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -576,7 +586,7 @@ Global {17E64F59-0E62-4FCE-BEC4-EABBCF95B9A2} = {BBF53739-168D-4635-8595-083AC0C65E4C} {AE09D1CA-5572-40BF-B984-74230E8634E1} = {14375E03-6BF8-45E6-B868-D2399368992B} {3E89B860-A428-470C-8E48-0DDABC4027F0} = {14375E03-6BF8-45E6-B868-D2399368992B} - {6CE969D2-A1E8-4BC1-85D8-303701B42F64} = {14375E03-6BF8-45E6-B868-D2399368992B} + {8B61CE3B-DC8A-47CE-A34B-38BC57DFFD57} = {14375E03-6BF8-45E6-B868-D2399368992B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {CC13D3AD-18BF-4695-AB2A-087EF0885B20} diff --git a/build/MTConnect.NET-DocsGen/CliInventory.cs b/build/MTConnect.NET-DocsGen/CliInventory.cs index e6ca63b0e..adc3bb23e 100644 --- a/build/MTConnect.NET-DocsGen/CliInventory.cs +++ b/build/MTConnect.NET-DocsGen/CliInventory.cs @@ -342,10 +342,15 @@ private static CliInfo CollectDotNetTool(string name, string file, string repoRo if (headerDescs.TryGetValue(flagName, out var headerDesc)) desc = headerDesc; desc ??= ExtractDotnetFlagDescription(text, flagName); - // Detect whether the case body calls `RequireValue` — if it - // does, the flag takes a value. + // Detect whether the case body calls `RequireValue` — if it does, + // the flag takes a value. The scan is bounded to the CURRENT case + // block only: it stops at the next `case "…":` label, a `default:` + // label, or a `break;` terminator, so a boolean flag whose case + // body sits above a value-taking case (like `--full-tree` above + // `case "--output": … RequireValue(…)`) does not falsely inherit + // the neighbor's value shape. bool takesValue = Regex.IsMatch(text, - $@"case\s+""{Regex.Escape(flagName)}""\s*:[\s\S]{{0,200}}?RequireValue"); + $@"case\s+""{Regex.Escape(flagName)}""\s*:(?:(?!\s*case\s+""|\s*default\s*:|\bbreak\s*;)[\s\S])*?RequireValue"); flags.Add(new CliFlag( Name: flagName, Short: null, diff --git a/build/MTConnect.NET-SysML-Import/CSharp/ClassModel.cs b/build/MTConnect.NET-SysML-Import/CSharp/ClassModel.cs index e737ed083..b37fd0ead 100644 --- a/build/MTConnect.NET-SysML-Import/CSharp/ClassModel.cs +++ b/build/MTConnect.NET-SysML-Import/CSharp/ClassModel.cs @@ -75,6 +75,22 @@ public class ClassModel : MTConnectClassModel, ITemplateModel /// public new List Properties { get; set; } = new(); + /// + /// true when at least one ancestor in the + /// chain declares a + /// non-empty array. + /// Model.scriban uses this — rather than mere parent + /// presence — to decide whether the generated Rules field + /// needs the new modifier. A class can have a parent + /// without that parent (or any of its ancestors) declaring + /// Rules, in which case emitting new hides nothing + /// and the compiler raises CS0109. Populated by + /// after every + /// has been assembled, so the full + /// ancestor chain is resolvable. + /// + public bool ParentHasRules { get; set; } + /// /// Parameterless constructor used by the import pipeline when it diff --git a/build/MTConnect.NET-SysML-Import/CSharp/EnumModel.cs b/build/MTConnect.NET-SysML-Import/CSharp/EnumModel.cs index be6b5358a..d8c83a92e 100644 --- a/build/MTConnect.NET-SysML-Import/CSharp/EnumModel.cs +++ b/build/MTConnect.NET-SysML-Import/CSharp/EnumModel.cs @@ -93,7 +93,7 @@ public string RenderModel() public string RenderDescriptions() { if (Values == null || Values.Count == 0) return null; - var template = TemplateLoader.LoadOrThrow("CSharp", "Templates", "EnumDescriptions.scriban"); + var template = TemplateLoader.LoadOrThrow("CSharp", "Templates", "EnumOrStringDescriptions.scriban"); return template.Render(this); } } diff --git a/build/MTConnect.NET-SysML-Import/CSharp/EnumStringModel.cs b/build/MTConnect.NET-SysML-Import/CSharp/EnumStringModel.cs index 654dacf1c..1e88f9c3c 100644 --- a/build/MTConnect.NET-SysML-Import/CSharp/EnumStringModel.cs +++ b/build/MTConnect.NET-SysML-Import/CSharp/EnumStringModel.cs @@ -14,6 +14,14 @@ internal class EnumStringModel : MTConnectEnumModel, ITemplateModel public bool IsPartial { get; set; } + // Consumed by the Shape-B consolidated EnumOrStringDescriptions.scriban + // template: gates the class-doc wording, the Get(...) overload's + // parameter type (string vs. enum-typed), and the Get(...) doc summary. + // EnumModel and ObservationModel do NOT expose this — Scriban resolves + // a missing member as null (falsy), producing the enum-shape emission + // for those two callers. + public bool IsString => true; + public EnumStringModel() { } @@ -88,7 +96,7 @@ public string RenderModel() public string RenderDescriptions() { - var template = TemplateLoader.LoadOrThrow("CSharp", "Templates", "EnumStringDescriptions.scriban"); + var template = TemplateLoader.LoadOrThrow("CSharp", "Templates", "EnumOrStringDescriptions.scriban"); return template.Render(this); } } diff --git a/build/MTConnect.NET-SysML-Import/CSharp/MeasurementModel.cs b/build/MTConnect.NET-SysML-Import/CSharp/MeasurementModel.cs index 5ac65a18f..2c9c01342 100644 --- a/build/MTConnect.NET-SysML-Import/CSharp/MeasurementModel.cs +++ b/build/MTConnect.NET-SysML-Import/CSharp/MeasurementModel.cs @@ -66,7 +66,11 @@ public string RenderModel() } /// - public string RenderInterface() => null; + public string RenderInterface() + { + var template = TemplateLoader.LoadOrThrow("CSharp", "Templates", "Pallets.MeasurementInterface.scriban"); + return template.Render(this); + } /// public string RenderDescriptions() => null; diff --git a/build/MTConnect.NET-SysML-Import/CSharp/ObservationModel.cs b/build/MTConnect.NET-SysML-Import/CSharp/ObservationModel.cs index b788e2a0a..d89a4f260 100644 --- a/build/MTConnect.NET-SysML-Import/CSharp/ObservationModel.cs +++ b/build/MTConnect.NET-SysML-Import/CSharp/ObservationModel.cs @@ -72,7 +72,7 @@ public string RenderModel() /// public string RenderDescriptions() { - var template = TemplateLoader.LoadOrThrow("CSharp", "Templates", "EnumDescriptions.scriban"); + var template = TemplateLoader.LoadOrThrow("CSharp", "Templates", "EnumOrStringDescriptions.scriban"); return template.Render(this); } } diff --git a/build/MTConnect.NET-SysML-Import/CSharp/TemplateRenderer.cs b/build/MTConnect.NET-SysML-Import/CSharp/TemplateRenderer.cs index 5a3e82745..e8f5a6ece 100644 --- a/build/MTConnect.NET-SysML-Import/CSharp/TemplateRenderer.cs +++ b/build/MTConnect.NET-SysML-Import/CSharp/TemplateRenderer.cs @@ -306,6 +306,15 @@ public static void Render(MTConnectModel mtconnectModel, string outputPath) // so its `Code` property hides Measurement.Code and needs `new`. MarkInheritedProperties(templates, classModels); + // Mark each ClassModel's ParentHasRules flag so Model.scriban + // emits the `new` modifier on the generated Rules[] field only + // when an ancestor actually declares Rules. Parent presence + // alone is not sufficient — e.g. Axis extends AbstractAxis, but + // AbstractAxis has no Rules, so `new` on Axis.Rules would hide + // nothing and raise CS0109 ("does not hide an accessible + // member"). See ClassModel.ParentHasRules XML doc. + MarkParentHasRules(templates, classModels); + foreach (var template in templates) { @@ -642,20 +651,19 @@ private static void MarkInheritedProperties( break; case "Assets.CuttingTools.ToolingMeasurement": - // ToolingMeasurement extends `Measurement` (the - // CuttingTools abstract Measurement base, NOT - // Assets.Pallet.Measurement). The CuttingTools - // Measurement.g.cs is hand-maintained / frozen — - // not produced by any current renderer flow — so - // it never enters the export-side ClassModel - // graph the inheritance walk traverses, and a - // Name-only lookup of "Measurement" resolves to - // Pallet.Measurement (which lacks Code). Class - // side only — IMeasurement.g.cs has `Code` - // commented out, so the interface child does NOT - // hide anything and emitting `new` there would - // produce CS0109 instead. - classOnlyNames.Add("Code"); + // No hand-stitched inheritance seed needed. The + // Assets.CuttingTools.Measurement base IS produced + // by the current renderer flow (via + // MTConnectAssetInformationModel.ParseAssetInformationModel's + // sharedMeasurement injection which imports the + // Pallet Measurement class under Assets.CuttingTools), + // so the export-side ClassModel graph already carries + // its property list. The Pallet Measurement lacks + // Code, and the interface IMeasurement.g.cs likewise + // has Code commented out — hence emitting `new` on + // ToolingMeasurement.Code would raise CS0109 on both + // the class and interface sides. Fall through to the + // default inheritance walk with no override. break; } @@ -701,6 +709,82 @@ private static void MarkInheritedProperties( } } + /// + /// Marks each flag by walking + /// the ancestor chain and + /// checking whether any ancestor declares a non-empty + /// array. Model.scriban + /// uses the flag to decide whether the generated Rules field + /// needs the new modifier — mere parent presence is not + /// sufficient, since a class can extend a parent that itself carries + /// no Rules (e.g. Axis : AbstractAxis, where + /// AbstractAxis has no Rules). Emitting new in + /// that case hides nothing and the compiler raises CS0109. + /// + /// + /// Deliberately independent of + /// rather than folded into its walk: that method's per-class loop + /// starts with if (!HasAnyProperties(template)) continue;, + /// which would skip the Rules-ancestor check for any class that + /// declares Rules but no Properties. Keeping the walk separate — at + /// the cost of rebuilding the byId/byName lookup tables — avoids + /// that guard clause entirely so every ClassModel with a parent gets + /// checked regardless of its own property count. + /// + private static void MarkParentHasRules( + List templates, + IEnumerable importClassModels) + { + if (templates == null) return; + + var classTemplates = templates.OfType().ToList(); + if (classTemplates.Count == 0) return; + + var byId = new Dictionary(StringComparer.Ordinal); + var byName = new Dictionary(StringComparer.Ordinal); + foreach (var ct in classTemplates) + { + if (!string.IsNullOrEmpty(ct.Id)) byId.TryAdd(ct.Id, ct); + if (!string.IsNullOrEmpty(ct.Name)) byName.TryAdd(ct.Name, ct); + } + if (importClassModels != null) + { + foreach (var cm in importClassModels) + { + if (cm == null) continue; + if (!string.IsNullOrEmpty(cm.Id)) byId.TryAdd(cm.Id, cm); + if (!string.IsNullOrEmpty(cm.Name)) byName.TryAdd(cm.Name, cm); + } + } + + foreach (var template in classTemplates) + { + if (template is not ClassModel classModel) continue; + if (string.IsNullOrEmpty(template.ParentName)) continue; + + var visited = new HashSet(StringComparer.Ordinal); + var currentId = template.Id; + var parentName = template.ParentName; + var parentHasRules = false; + + while (!string.IsNullOrEmpty(parentName)) + { + var parent = ResolveParent(currentId, parentName, byId, byName); + if (parent == null) break; + if (!visited.Add(parent.Id ?? parentName)) break; + if (parent.Rules != null && parent.Rules.Length > 0) + { + parentHasRules = true; + break; + } + currentId = parent.Id; + parentName = parent.ParentName; + } + + classModel.ParentHasRules = parentHasRules; + } + } + /// /// Resolves a parent ClassModel from /// (a bare ClassName as stored in diff --git a/build/MTConnect.NET-SysML-Import/CSharp/Templates/EnumDescriptions.scriban b/build/MTConnect.NET-SysML-Import/CSharp/Templates/EnumOrStringDescriptions.scriban similarity index 53% rename from build/MTConnect.NET-SysML-Import/CSharp/Templates/EnumDescriptions.scriban rename to build/MTConnect.NET-SysML-Import/CSharp/Templates/EnumOrStringDescriptions.scriban index 16691ed33..23d908b3d 100644 --- a/build/MTConnect.NET-SysML-Import/CSharp/Templates/EnumDescriptions.scriban +++ b/build/MTConnect.NET-SysML-Import/CSharp/Templates/EnumOrStringDescriptions.scriban @@ -1,10 +1,15 @@ // Copyright (c) 2024 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. +{{-# Shape-B consolidated Descriptions template. Valid for every MTConnect version. #}} +{{-# Covers both the enum-descriptions and the string-constant-descriptions callers. #}} +{{-# When is_string is truthy, the Get(...) overload takes a `string value` and the #}} +{{-# class doc reads "string constant" instead of "value"; when falsy, the Get(...) #}} +{{-# overload takes an enum-typed value and the class doc reads "value". #}} namespace {{namespace}} { /// - /// Description text for each value as defined by the MTConnect Standard. + /// Description text for each {{ if is_string }}string constant{{ else }}value{{ end }} as defined by the MTConnect Standard. /// public static class {{name}}Descriptions { @@ -21,9 +26,9 @@ namespace {{namespace}} /// - /// Returns the MTConnect Standard description text for the specified value, or null when none is defined. + /// Returns the MTConnect Standard description text for the specified{{ if is_string }}{{ else }} {{ end }} value, or null when none is defined. /// - public static string Get({{name}} value) + public static string Get({{ if is_string }}string{{ else }}{{name}}{{ end }} value) { switch (value) { diff --git a/build/MTConnect.NET-SysML-Import/CSharp/Templates/EnumStringDescriptions.scriban b/build/MTConnect.NET-SysML-Import/CSharp/Templates/EnumStringDescriptions.scriban deleted file mode 100644 index f85216280..000000000 --- a/build/MTConnect.NET-SysML-Import/CSharp/Templates/EnumStringDescriptions.scriban +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. -// TrakHound Inc. licenses this file to you under the MIT license. - -namespace {{namespace}} -{ - /// - /// Description text for each string constant as defined by the MTConnect Standard. - /// - public static class {{name}}Descriptions - { -{{- i = 0 }}{{- for value in values }}{{ i = i + 1 }} - /// - /// {{value.description}} - /// - public const string {{value.name}} = "{{value.description}}"; - {{- if (i < (values | array.size)) }} - {{ end }} -{{- end }} - -{{- if ((values | array.size) > 0) }}{{ i = 0 }} - - - /// - /// Returns the MTConnect Standard description text for the specified value, or null when none is defined. - /// - public static string Get(string value) - { - switch (value) - { -{{- for value in values }}{{ i = i + 1 }} - case {{name}}.{{value.name}}: return "{{value.description}}"; -{{- end }} - } - - return null; - } -{{- end }} - } -} \ No newline at end of file diff --git a/build/MTConnect.NET-SysML-Import/CSharp/Templates/Model.scriban b/build/MTConnect.NET-SysML-Import/CSharp/Templates/Model.scriban index 5e118e562..705b8a038 100644 --- a/build/MTConnect.NET-SysML-Import/CSharp/Templates/Model.scriban +++ b/build/MTConnect.NET-SysML-Import/CSharp/Templates/Model.scriban @@ -24,7 +24,7 @@ namespace {{namespace}} /// SysML model, preserved verbatim so downstream consumers can /// inspect the spec's raw validation rules at runtime. /// - public {{ if (parent_name) }}new {{ end }}static readonly string[] Rules = new[] + public {{ if (parent_has_rules) }}new {{ end }}static readonly string[] Rules = new[] { {{- for rule in rules }}{{ if (!for.last) }} "{{ rule | string.replace `\` `\\` | string.replace `"` `\"` | string.replace "\r" "\\r" | string.replace "\n" "\\n" | string.replace "\t" "\\t" }}", diff --git a/build/MTConnect.NET-SysML-Import/CSharp/Templates/Pallets.MeasurementInterface.scriban b/build/MTConnect.NET-SysML-Import/CSharp/Templates/Pallets.MeasurementInterface.scriban new file mode 100644 index 000000000..97dcf30ea --- /dev/null +++ b/build/MTConnect.NET-SysML-Import/CSharp/Templates/Pallets.MeasurementInterface.scriban @@ -0,0 +1,12 @@ +// Copyright (c) 2025 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +namespace {{namespace}} +{ + /// + /// {{description}} + /// + public interface I{{name}} : IMeasurement + { + } +} \ No newline at end of file diff --git a/build/MTConnect.NET-SysML-Import/Json-cppagent/TemplateRenderer.cs b/build/MTConnect.NET-SysML-Import/Json-cppagent/TemplateRenderer.cs index 02651e239..367368634 100644 --- a/build/MTConnect.NET-SysML-Import/Json-cppagent/TemplateRenderer.cs +++ b/build/MTConnect.NET-SysML-Import/Json-cppagent/TemplateRenderer.cs @@ -36,7 +36,7 @@ private static void WriteComponents(MTConnectModel mtconnectModel, string output var componentsModel = new ComponentsModel(); var components = mtconnectModel.DeviceInformationModel.Components.Types; - foreach (var component in components.OrderBy(o => o.Type)) componentsModel.Types.Add(component); + foreach (var component in components.Where(o => !IsDeprecated(o.Deprecated)).OrderBy(o => o.Type)) componentsModel.Types.Add(component); RenderTo("Components.scriban", componentsModel, "Devices/JsonComponents", outputPath); } @@ -46,7 +46,7 @@ private static void WriteEvents(MTConnectModel mtconnectModel, string outputPath var dataItemsModel = new DataItemsModel(); var dataItems = mtconnectModel.DeviceInformationModel.DataItems.Types; - foreach (var dataItem in dataItems.Where(o => o.Category == "EVENT").OrderBy(o => o.Type)) dataItemsModel.Types.Add(dataItem); + foreach (var dataItem in dataItems.Where(o => o.Category == "EVENT" && !IsDeprecated(o.Deprecated)).OrderBy(o => o.Type)) dataItemsModel.Types.Add(dataItem); RenderTo("Events.scriban", dataItemsModel, "Streams/JsonEvents", outputPath); } @@ -56,11 +56,23 @@ private static void WriteSamples(MTConnectModel mtconnectModel, string outputPat var dataItemsModel = new DataItemsModel(); var dataItems = mtconnectModel.DeviceInformationModel.DataItems.Types; - foreach (var dataItem in dataItems.Where(o => o.Category == "SAMPLE").OrderBy(o => o.Type)) dataItemsModel.Types.Add(dataItem); + foreach (var dataItem in dataItems.Where(o => o.Category == "SAMPLE" && !IsDeprecated(o.Deprecated)).OrderBy(o => o.Type)) dataItemsModel.Types.Add(dataItem); RenderTo("Samples.scriban", dataItemsModel, "Streams/JsonSamples", outputPath); } + // A Component/DataItem type counts as deprecated exactly when the + // CSharp generator's own templates would stamp it + // [System.Obsolete] — see Devices.ComponentType.scriban and + // Devices.DataItemType.scriban, both guarded by the identical + // `{{- if (deprecated) }}` check against the model's `Deprecated` + // string. Mirroring that predicate here keeps the two generators + // in lockstep: the JSON-cppagent tree never references a Common + // type the Common tree itself marks obsolete, so regeneration can + // never reintroduce the CS0618-under-TreatWarningsAsErrors failure + // class PR #233 exposed. + private static bool IsDeprecated(string deprecated) => !string.IsNullOrEmpty(deprecated); + private static void WriteCuttingToolMeasurements(MTConnectModel mtconnectModel, string outputPath) { var measurementsModel = new CuttingToolMeasurementsModel(); diff --git a/build/MTConnect.NET-SysML-Import/Program.cs b/build/MTConnect.NET-SysML-Import/Program.cs index b4ad131b7..001da39bb 100644 --- a/build/MTConnect.NET-SysML-Import/Program.cs +++ b/build/MTConnect.NET-SysML-Import/Program.cs @@ -2,39 +2,100 @@ using MTConnect.SysML.CSharp; using MTConnect.SysML.Json_cppagent; using MTConnect.SysML.Xml; +using System.Diagnostics; using System.Linq; +using System.Text; using System.Text.Json; +using System.Text.RegularExpressions; // SysML importer entry point. Runs on Linux / macOS / Windows / CI. // // Usage: // dotnet run --project build/MTConnect.NET-SysML-Import \ -// -- --xmi \ +// -- --new-xmi \ // --output \ +// [--previous-xmi ] \ +// [--compat-version-label public string AssetId { get; set; } + /// /// Technical information about an entity describing its physical layout, functional characteristics, and relationships with other entities. /// public MTConnect.Devices.Configurations.IConfiguration Configuration { get; set; } + /// /// Textual description for Asset. /// public string Description { get; set; } + /// /// Associated piece of equipment's UUID that supplied the Asset's data.uuid defined in Device Information Model. /// public string DeviceUuid { get; set; } + /// /// Condensed message digest from a secure one-way hash function. FIPS PUB 180-4 /// public string Hash { get; set; } + /// /// /// public System.Collections.Generic.IEnumerable Manufacturers { get; set; } + /// /// /// public string Model { get; set; } + /// /// Indicator that the Asset has been removed from the piece of equipment. /// public bool Removed { get; set; } + /// /// /// public string SerialNumber { get; set; } + /// /// /// public string Station { get; set; } + /// /// Time the Asset data was last modified. diff --git a/libraries/MTConnect.NET-Common/Assets/ComponentConfigurationParameters/Parameter.g.cs b/libraries/MTConnect.NET-Common/Assets/ComponentConfigurationParameters/Parameter.g.cs index a628a796f..1217b7fa6 100644 --- a/libraries/MTConnect.NET-Common/Assets/ComponentConfigurationParameters/Parameter.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/ComponentConfigurationParameters/Parameter.g.cs @@ -20,31 +20,37 @@ public class Parameter : IParameter /// Internal identifier, register, or address. /// public string Identifier { get; set; } + /// /// Maximum allowed value. /// public double? Maximum { get; set; } + /// /// Minimal allowed value. /// public double? Minimum { get; set; } + /// /// Descriptive name. /// public string Name { get; set; } + /// /// Nominal value. /// public double? Nominal { get; set; } + /// /// Engineering units.units **SHOULD** be SI or MTConnect Units. /// public string Units { get; set; } + /// /// Configured value. diff --git a/libraries/MTConnect.NET-Common/Assets/ComponentConfigurationParameters/ParameterSet.g.cs b/libraries/MTConnect.NET-Common/Assets/ComponentConfigurationParameters/ParameterSet.g.cs index f5f988461..4f4a94b68 100644 --- a/libraries/MTConnect.NET-Common/Assets/ComponentConfigurationParameters/ParameterSet.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/ComponentConfigurationParameters/ParameterSet.g.cs @@ -20,6 +20,7 @@ public class ParameterSet : IParameterSet /// Name of the parameter set if more than one exists. /// public string Name { get; set; } + /// /// Property that determines the characteristic or behavior of an entity. diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingItem.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingItem.g.cs index 575d797f4..eaa9abed9 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingItem.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingItem.g.cs @@ -20,46 +20,55 @@ public partial class CuttingItem : ICuttingItem /// Status of the cutting tool. /// public System.Collections.Generic.IEnumerable CutterStatus { get; set; } + /// /// Free-form description of the cutting item. /// public string Description { get; set; } + /// /// Material composition for this cutting item. /// public string Grade { get; set; } + /// /// Number or numbers representing the individual cutting item or items on the tool.Indices **SHOULD** start numbering with the inserts or CuttingItem furthest from the gauge line and increasing in value as the items get closer to the gauge line. Items at the same distance **MAY** be arbitrarily numbered.> Note: In XML, the representation **MUST** be a single number ('1') or a comma separated set of individual elements ('1,2,3,4'), or as a inclusive range of values as in ('1-10') or any combination of ranges and numbers as in '1-4,6-10,22'. There **MUST NOT** be spaces or non-integer values in the text representation. /// public string Indices { get; set; } + /// /// Manufacturer identifier of this cutting item. /// public string ItemId { get; set; } + /// /// The tool life measured in tool wear. /// public System.Collections.Generic.IEnumerable ItemLife { get; set; } + /// /// Free form description of the location on the cutting tool.Locus **MAY** be any free form string, but **SHOULD** adhere to the following rules:* The location numbering **SHOULD** start at the furthest CuttingItem and work it’s way back to the CuttingItem closest to the gauge line.* Flutes **SHOULD** be identified as such using the word `FLUTE`:. For example: `FLUTE`: 1, `INSERT`: 2 - would indicate the first flute and the second furthest insert from the end of the tool on that flute.* Other designations such as `CARTRIDGE` **MAY** be included, but should be identified using upper case and followed by a colon (:). /// public string Locus { get; set; } + /// /// Manufacturers of the cutting item.This will reference the tool item and adaptive items specifically. The cutting itemsmanufacturers’ will be a property of CuttingItem.> Note: In XML, the representation **MUST** be a comma(,) delimited list of manufacturer names. See CuttingItem Schema Diagrams. /// public System.Collections.Generic.IEnumerable Manufacturers { get; set; } + /// /// A collection of measurements relating to this cutting item. /// public System.Collections.Generic.IEnumerable Measurements { get; set; } + /// /// Tool group this item is assigned in the part program. diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolArchetypeAsset.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolArchetypeAsset.g.cs index b4b3d6c32..cc7f7ee2f 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolArchetypeAsset.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolArchetypeAsset.g.cs @@ -20,16 +20,19 @@ public partial class CuttingToolArchetypeAsset : Asset, ICuttingToolArchetypeAss /// Detailed structure of the cutting tool which is static during its lifecycle. ISO 13399. /// public MTConnect.Assets.CuttingTools.ICuttingToolDefinition CuttingToolDefinition { get; set; } + /// /// Data regarding the application or use of the tool.This data is provided by various pieces of equipment (i.e. machine tool, presetter) and statistical process control applications. Life cycle data will not remain static, but will change periodically when a tool is used or measured. /// public MTConnect.Assets.CuttingTools.ICuttingToolLifeCycle CuttingToolLifeCycle { get; set; } + /// /// Unique identifier for this assembly. /// public new string SerialNumber { get; set; } + /// /// Identifier for a class of cutting tools. diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolArchetypeReference.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolArchetypeReference.g.cs index 2be636e5a..9d20ff084 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolArchetypeReference.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolArchetypeReference.g.cs @@ -20,6 +20,7 @@ public class CuttingToolArchetypeReference : ICuttingToolArchetypeReference /// URL of the CuttingToolArchetype information model. /// public string Source { get; set; } + /// /// `assetId` of the related CuttingToolArchetype. diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolAsset.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolAsset.g.cs index 1fa37a4ac..78fd6e8ec 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolAsset.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolAsset.g.cs @@ -20,21 +20,25 @@ public partial class CuttingToolAsset : Asset, ICuttingToolAsset /// AssetId and/or the URL of the data source of CuttingToolArchetype. /// public MTConnect.Assets.CuttingTools.ICuttingToolArchetypeReference CuttingToolArchetypeReference { get; set; } + /// /// Detailed structure of the cutting tool which is static during its lifecycle. ISO 13399. /// public MTConnect.Assets.CuttingTools.ICuttingToolDefinition CuttingToolDefinition { get; set; } + /// /// Data regarding the application or use of the tool.This data is provided by various pieces of equipment (i.e. machine tool, presetter) and statistical process control applications. Life cycle data will not remain static, but will change periodically when a tool is used or measured. /// public MTConnect.Assets.CuttingTools.ICuttingToolLifeCycle CuttingToolLifeCycle { get; set; } + /// /// Unique identifier for this assembly. /// public new string SerialNumber { get; set; } + /// /// Identifier for a class of cutting tools. diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolDefinition.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolDefinition.g.cs index 7c67aec2b..ceebbdd99 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolDefinition.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolDefinition.g.cs @@ -20,6 +20,7 @@ public class CuttingToolDefinition : ICuttingToolDefinition /// Identifies the expected representation of the enclosed data. /// public MTConnect.Assets.CuttingTools.FormatType Format { get; set; } + /// /// Format. diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolLifeCycle.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolLifeCycle.g.cs index 6610a3e69..e4db3287a 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolLifeCycle.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/CuttingToolLifeCycle.g.cs @@ -20,51 +20,61 @@ public partial class CuttingToolLifeCycle : ICuttingToolLifeCycle /// Identifier for the capability to connect any component of the cutting tool together, except Assembly Items, on the machine side. Code: `CCMS` /// public string ConnectionCodeMachineSide { get; set; } + /// /// Status of the cutting tool. /// public System.Collections.Generic.IEnumerable CutterStatus { get; set; } + /// /// Part of of the tool that physically removes the material from the workpiece by shear deformation. /// public System.Collections.Generic.IEnumerable CuttingItems { get; set; } + /// /// Location of the pot or spindle the cutting tool currently resides in.positiveOverlap is provided, the tool reserves additional locations on either side, otherwise if they are not given, no additional locations are required for this tool.positiveOverlap of 1, the first pot **MAY** be occupied as well. /// public MTConnect.Assets.CuttingTools.ILocation Location { get; set; } + /// /// Constrained scalar value associated with a cutting tool. /// public System.Collections.Generic.IEnumerable Measurements { get; set; } + /// /// Constrained process feed rate for the tool in mm/s.minimum **MUST** be specified. /// public MTConnect.Assets.CuttingTools.IProcessFeedRate ProcessFeedRate { get; set; } + /// /// Constrained process spindle speed for the tool in revolutions/minute.minimum **MUST** be specified. /// public MTConnect.Assets.CuttingTools.IProcessSpindleSpeed ProcessSpindleSpeed { get; set; } + /// /// Tool group this tool is assigned in the part program. /// public string ProgramToolGroup { get; set; } + /// /// Number of the tool as referenced in the part program. /// public string ProgramToolNumber { get; set; } + /// /// Number of times the cutter has been reconditioned. /// public MTConnect.Assets.CuttingTools.IReconditionCount ReconditionCount { get; set; } + /// /// Cutting tool life as related to the assembly. diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ItemLife.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ItemLife.g.cs index 2dc1f81f6..dc1c37297 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ItemLife.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ItemLife.g.cs @@ -20,26 +20,31 @@ public class ItemLife : IItemLife /// Indicates if the item life counts from zero to maximum or maximum to zero. /// public MTConnect.Assets.CuttingTools.CountDirectionType CountDirection { get; set; } + /// /// Initial life of the item when it is new. /// public double? Initial { get; set; } + /// /// End of life limit for this item. /// public double? Limit { get; set; } + /// /// Type of item life being accumulated. /// public MTConnect.Assets.CuttingTools.ToolLifeType Type { get; set; } + /// /// Value of ItemLife. /// public double Value { get; set; } + /// /// Point at which a item life warning will be raised. diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/Location.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/Location.g.cs index 97f1ba637..164283482 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/Location.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/Location.g.cs @@ -20,41 +20,49 @@ public class Location : ILocation /// Automatic tool changer associated with a tool. /// public string AutomaticToolChanger { get; set; } + /// /// Number of locations at lower index values from this location. /// public int? NegativeOverlap { get; set; } + /// /// Number of locations at higher index value from this location. /// public int? PositiveOverlap { get; set; } + /// /// Tool bar associated with a tool. /// public string ToolBar { get; set; } + /// /// Tool magazine associated with a tool. /// public string ToolMagazine { get; set; } + /// /// Tool rack associated with a tool. /// public string ToolRack { get; set; } + /// /// Turret associated with a tool. /// public string Turret { get; set; } + /// /// Type of location being identified. value**MUST** be a numeric value. /// public MTConnect.Assets.CuttingTools.LocationType Type { get; set; } + /// /// diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/Measurement.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/Measurement.g.cs index de4754402..e6afa5399 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/Measurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/Measurement.g.cs @@ -1,56 +1,57 @@ // Copyright (c) 2024 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. -// MTConnect SysML v2.3 : UML ID = EAID_C09F377D_8946_421b_B746_E23C01D97EAC +// MTConnect SysML v2.3 : UML ID = _2024x_68e0225_1727793846441_986747_23754 namespace MTConnect.Assets.CuttingTools { /// - /// Constrained scalar value associated with a cutting tool. + /// Constrained scalar value associated with an Asset /// public partial class Measurement : IMeasurement { /// /// The description of this type as defined by the MTConnect Standard. /// - public const string DescriptionText = "Constrained scalar value associated with a cutting tool."; + public const string DescriptionText = "Constrained scalar value associated with an Asset"; - /// - /// Shop specific code for the measurement. ISO 13399 codes **MAY** be used for these codes as well. code values. - /// - public string Code { get; set; } - /// /// Maximum value for the measurement. /// public double? Maximum { get; set; } + /// /// Minimum value for the measurement. /// public double? Minimum { get; set; } + /// /// NativeUnits. /// public string NativeUnits { get; set; } + /// /// As advertised value for the measurement. /// public double? Nominal { get; set; } + /// /// Number of significant digits in the reported value. /// public int? SignificantDigits { get; set; } + /// /// Units. /// public string Units { get; set; } + /// /// /// diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ProcessFeedRate.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ProcessFeedRate.g.cs index 6ed1b3c8e..e7159796c 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ProcessFeedRate.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ProcessFeedRate.g.cs @@ -20,16 +20,19 @@ public class ProcessFeedRate : IProcessFeedRate /// Upper bound for the tool’s process target feedrate. /// public double? Maximum { get; set; } + /// /// Lower bound for the tool's feedrate. /// public double? Minimum { get; set; } + /// /// Nominal feedrate the tool is designed to operate at. /// public double? Nominal { get; set; } + /// /// diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ProcessSpindleSpeed.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ProcessSpindleSpeed.g.cs index 2ad2bc015..cefb5be97 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ProcessSpindleSpeed.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ProcessSpindleSpeed.g.cs @@ -20,16 +20,19 @@ public class ProcessSpindleSpeed : IProcessSpindleSpeed /// Upper bound for the tool’s target spindle speed. /// public double? Maximum { get; set; } + /// /// Lower bound for the tools spindle speed. /// public double? Minimum { get; set; } + /// /// Nominal speed the tool is designed to operate at. /// public double? Nominal { get; set; } + /// /// diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ReconditionCount.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ReconditionCount.g.cs index e0e56122b..a565cecfd 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ReconditionCount.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ReconditionCount.g.cs @@ -20,6 +20,7 @@ public class ReconditionCount : IReconditionCount /// Maximum number of times the tool may be reconditioned. /// public int? MaximumCount { get; set; } + /// /// CuttingToolLifeCycle. diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ToolLife.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ToolLife.g.cs index 4cc0b9479..c78fb2ed0 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ToolLife.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ToolLife.g.cs @@ -20,26 +20,31 @@ public partial class ToolLife : IToolLife /// Indicates if the tool life counts from zero to maximum or maximum to zero. /// public MTConnect.Assets.CuttingTools.CountDirectionType CountDirection { get; set; } + /// /// Initial life of the tool when it is new. /// public double? Initial { get; set; } + /// /// End of life limit for the tool. /// public double? Limit { get; set; } + /// /// Type of tool life being accumulated. /// public MTConnect.Assets.CuttingTools.ToolLifeType Type { get; set; } + /// /// Value of ToolLife. /// public double Value { get; set; } + /// /// Point at which a tool life warning will be raised. diff --git a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ToolingMeasurement.g.cs b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ToolingMeasurement.g.cs index 385e7e41e..e0292917b 100644 --- a/libraries/MTConnect.NET-Common/Assets/CuttingTools/ToolingMeasurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/CuttingTools/ToolingMeasurement.g.cs @@ -19,6 +19,6 @@ public partial class ToolingMeasurement : Measurement, IToolingMeasurement /// /// Shop specific code for the measurement. ISO 13399 codes **MAY** be used for these codes as well. code values. /// - public new string Code { get; set; } + public string Code { get; set; } } } \ No newline at end of file diff --git a/libraries/MTConnect.NET-Common/Assets/Files/AbstractFileAsset.g.cs b/libraries/MTConnect.NET-Common/Assets/Files/AbstractFileAsset.g.cs index 68daf0fa5..e09b9b032 100644 --- a/libraries/MTConnect.NET-Common/Assets/Files/AbstractFileAsset.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Files/AbstractFileAsset.g.cs @@ -20,26 +20,31 @@ public abstract partial class AbstractFileAsset : Asset, IAbstractFileAsset /// Category of application that will use this file. /// public MTConnect.Assets.Files.ApplicationCategory ApplicationCategory { get; set; } + /// /// Type of application that will use this file. /// public MTConnect.Assets.Files.ApplicationType ApplicationType { get; set; } + /// /// Remark or interpretation for human interpretation associated with a File or FileArchetype. /// public System.Collections.Generic.IEnumerable FileComments { get; set; } + /// /// Key-value pair providing additional metadata about a File. /// public System.Collections.Generic.IEnumerable FileProperties { get; set; } + /// /// Mime type of the file. /// public string MediaType { get; set; } + /// /// Name of the file. diff --git a/libraries/MTConnect.NET-Common/Assets/Files/FileAsset.g.cs b/libraries/MTConnect.NET-Common/Assets/Files/FileAsset.g.cs index c738c5d11..b4f05955c 100644 --- a/libraries/MTConnect.NET-Common/Assets/Files/FileAsset.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Files/FileAsset.g.cs @@ -20,41 +20,49 @@ public partial class FileAsset : AbstractFileAsset, IFileAsset /// Time the file was created. /// public System.DateTime CreationTime { get; set; } + /// /// Reference to the target Device for this File. /// public System.Collections.Generic.IEnumerable Destinations { get; set; } + /// /// URL reference to the file location. /// public MTConnect.Assets.Files.IFileLocation Location { get; set; } + /// /// Time the file was modified. /// public System.DateTime? ModificationTime { get; set; } + /// /// Public key used to verify the signature. /// public string PublicKey { get; set; } + /// /// Secure hash of the file. /// public string Signature { get; set; } + /// /// Size of the file in bytes. /// public int Size { get; set; } + /// /// State of the file. /// public MTConnect.Assets.Files.FileState State { get; set; } + /// /// Version identifier of the file. diff --git a/libraries/MTConnect.NET-Common/Assets/Files/FileComment.g.cs b/libraries/MTConnect.NET-Common/Assets/Files/FileComment.g.cs index a5e91f1cf..5588683ad 100644 --- a/libraries/MTConnect.NET-Common/Assets/Files/FileComment.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Files/FileComment.g.cs @@ -20,6 +20,7 @@ public class FileComment : IFileComment /// Time the comment was made. /// public System.DateTime Timestamp { get; set; } + /// /// Text of the comment about the file. diff --git a/libraries/MTConnect.NET-Common/Assets/Files/FileLocation.g.cs b/libraries/MTConnect.NET-Common/Assets/Files/FileLocation.g.cs index 02f6cfcfa..efb406293 100644 --- a/libraries/MTConnect.NET-Common/Assets/Files/FileLocation.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Files/FileLocation.g.cs @@ -20,6 +20,7 @@ public class FileLocation : IFileLocation /// URL reference to the file.`href` is of type `xlink:href` from the W3C XLink specification. /// public string Href { get; set; } + /// /// Type of href for the xlink href type. **MUST** be `locator` referring to a URL. diff --git a/libraries/MTConnect.NET-Common/Assets/Files/FileProperty.g.cs b/libraries/MTConnect.NET-Common/Assets/Files/FileProperty.g.cs index afd944148..fcb6a0f89 100644 --- a/libraries/MTConnect.NET-Common/Assets/Files/FileProperty.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Files/FileProperty.g.cs @@ -20,6 +20,7 @@ public class FileProperty : IFileProperty /// Name of the FileProperty. /// public string Name { get; set; } + /// /// The value of the FileProperty. diff --git a/libraries/MTConnect.NET-Common/Assets/Files/IAbstractFile.g.cs b/libraries/MTConnect.NET-Common/Assets/Files/IAbstractFile.g.cs deleted file mode 100644 index 3198b4690..000000000 --- a/libraries/MTConnect.NET-Common/Assets/Files/IAbstractFile.g.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. -// TrakHound Inc. licenses this file to you under the MIT license. - -namespace MTConnect.Assets.Files -{ - /// - /// Abstract Asset that contains the common properties of the File and FileArchetype types. - /// - public interface IAbstractFile : IAsset - { - /// - /// Category of application that will use this file. - /// - MTConnect.Assets.Files.ApplicationCategory ApplicationCategory { get; } - - /// - /// Type of application that will use this file. - /// - MTConnect.Assets.Files.ApplicationType ApplicationType { get; } - - /// - /// Remark or interpretation for human interpretation associated with a File or FileArchetype. - /// - System.Collections.Generic.IEnumerable FileComments { get; } - - /// - /// Key-value pair providing additional metadata about a File. - /// - System.Collections.Generic.IEnumerable FileProperties { get; } - - /// - /// Mime type of the file. - /// - string MediaType { get; } - - /// - /// Name of the file. - /// - string Name { get; } - } -} \ No newline at end of file diff --git a/libraries/MTConnect.NET-Common/Assets/Files/IFileArchetype.g.cs b/libraries/MTConnect.NET-Common/Assets/Files/IFileArchetype.g.cs deleted file mode 100644 index ed35e2e25..000000000 --- a/libraries/MTConnect.NET-Common/Assets/Files/IFileArchetype.g.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. -// TrakHound Inc. licenses this file to you under the MIT license. - -namespace MTConnect.Assets.Files -{ - /// - /// AbstractFile type that provides information common to all versions of a file. - /// - public interface IFileArchetype : IAbstractFile - { - } -} \ No newline at end of file diff --git a/libraries/MTConnect.NET-Common/Assets/Fixture/FixtureAsset.g.cs b/libraries/MTConnect.NET-Common/Assets/Fixture/FixtureAsset.g.cs index e6895c1e5..a0fffd5a3 100644 --- a/libraries/MTConnect.NET-Common/Assets/Fixture/FixtureAsset.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Fixture/FixtureAsset.g.cs @@ -20,16 +20,19 @@ public partial class FixtureAsset : PhysicalAsset, IFixtureAsset /// Actuation type of the Fixture's clamping mechanism. /// public string ClampingMethod { get; set; } + /// /// Identifier of the Pallet. /// public string FixtureId { get; set; } + /// /// Number or sequence assigned to the Fixture in a group of Fixtures. /// public int FixtureNumber { get; set; } + /// /// Actuation type of the Fixture's mounting mechanism. diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/IHeightMeasurement.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/IHeightMeasurement.g.cs index d6856276d..f89def2f4 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/IHeightMeasurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/IHeightMeasurement.g.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2025 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. namespace MTConnect.Assets.Pallet diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/ILengthMeasurement.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/ILengthMeasurement.g.cs index 7323449c7..c07133c1f 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/ILengthMeasurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/ILengthMeasurement.g.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2025 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. namespace MTConnect.Assets.Pallet diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedHeightMeasurement.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedHeightMeasurement.g.cs index b14910f4f..2319758ea 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedHeightMeasurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedHeightMeasurement.g.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2025 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. namespace MTConnect.Assets.Pallet diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedLengthMeasurement.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedLengthMeasurement.g.cs index 716016ba0..047707089 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedLengthMeasurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedLengthMeasurement.g.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2025 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. namespace MTConnect.Assets.Pallet diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedSwingMeasurement.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedSwingMeasurement.g.cs index 05f4d3ca9..3024f1dba 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedSwingMeasurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedSwingMeasurement.g.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2025 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. namespace MTConnect.Assets.Pallet diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedWeightMeasurement.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedWeightMeasurement.g.cs index 292fe40d9..8b7811564 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedWeightMeasurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedWeightMeasurement.g.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2025 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. namespace MTConnect.Assets.Pallet diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedWidthMeasurement.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedWidthMeasurement.g.cs index b3ffe8213..699b9761c 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedWidthMeasurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/ILoadedWidthMeasurement.g.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2025 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. namespace MTConnect.Assets.Pallet diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/ISwingMeasurement.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/ISwingMeasurement.g.cs index 2e08f0941..7a89acfef 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/ISwingMeasurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/ISwingMeasurement.g.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2025 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. namespace MTConnect.Assets.Pallet diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/IWeightMeasurement.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/IWeightMeasurement.g.cs index 4c4d9cd07..795c83e4a 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/IWeightMeasurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/IWeightMeasurement.g.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2025 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. namespace MTConnect.Assets.Pallet diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/IWidthMeasurement.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/IWidthMeasurement.g.cs index b24346c1f..fbdd15f4f 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/IWidthMeasurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/IWidthMeasurement.g.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2024 TrakHound Inc., All Rights Reserved. +// Copyright (c) 2025 TrakHound Inc., All Rights Reserved. // TrakHound Inc. licenses this file to you under the MIT license. namespace MTConnect.Assets.Pallet diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/Measurement.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/Measurement.g.cs index ebb607274..6cde906cc 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/Measurement.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/Measurement.g.cs @@ -20,31 +20,37 @@ public partial class Measurement : IMeasurement /// Maximum value for the measurement. /// public double? Maximum { get; set; } + /// /// Minimum value for the measurement. /// public double? Minimum { get; set; } + /// /// NativeUnits. /// public string NativeUnits { get; set; } + /// /// As advertised value for the measurement. /// public double? Nominal { get; set; } + /// /// Number of significant digits in the reported value. /// public int? SignificantDigits { get; set; } + /// /// Units. /// public string Units { get; set; } + /// /// diff --git a/libraries/MTConnect.NET-Common/Assets/Pallet/PalletAsset.g.cs b/libraries/MTConnect.NET-Common/Assets/Pallet/PalletAsset.g.cs index eec208381..cd392755f 100644 --- a/libraries/MTConnect.NET-Common/Assets/Pallet/PalletAsset.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/Pallet/PalletAsset.g.cs @@ -20,21 +20,25 @@ public partial class PalletAsset : PhysicalAsset, IPalletAsset /// Actuation type of the Pallet's clamping mechanism. /// public string ClampingMethod { get; set; } + /// /// Actuation type of the Pallet's mounting mechanism. /// public string MountingMethod { get; set; } + /// /// Identifier of the Pallet. /// public string PalletId { get; set; } + /// /// Number or sequence assigned to the Pallet in a group of Pallets. /// public int PalletNumber { get; set; } + /// /// Type of Pallet. Common types of pallet include: Process, Warehouse, Shipping, Fixture and Machine. diff --git a/libraries/MTConnect.NET-Common/Assets/PhysicalAsset.g.cs b/libraries/MTConnect.NET-Common/Assets/PhysicalAsset.g.cs index a348806ce..dfcfc61c3 100644 --- a/libraries/MTConnect.NET-Common/Assets/PhysicalAsset.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/PhysicalAsset.g.cs @@ -20,21 +20,25 @@ public partial class PhysicalAsset : IPhysicalAsset /// Date of calibration of the Asset. /// public System.DateTime CalibrationDate { get; set; } + /// /// Date of last inspection of the Asset. /// public System.DateTime InspectionDate { get; set; } + /// /// Date of creation or built of the Asset. /// public System.DateTime ManufactureDate { get; set; } + /// /// Constrained scalar value associated with an Asset /// public MTConnect.Assets.CuttingTools.IMeasurement Measurement { get; set; } + /// /// Date of next inspection of the Asset. diff --git a/libraries/MTConnect.NET-Common/Assets/QIF/QIFDocumentWrapperAsset.g.cs b/libraries/MTConnect.NET-Common/Assets/QIF/QIFDocumentWrapperAsset.g.cs index a3e53bcb9..0c3e9f63f 100644 --- a/libraries/MTConnect.NET-Common/Assets/QIF/QIFDocumentWrapperAsset.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/QIF/QIFDocumentWrapperAsset.g.cs @@ -20,6 +20,7 @@ public partial class QIFDocumentWrapperAsset : Asset, IQIFDocumentWrapperAsset /// QIF Document as given by the QIF standard. /// public string QIFDocument { get; set; } + /// /// Contained QIF Document type as defined in the QIF Standard. diff --git a/libraries/MTConnect.NET-Common/Assets/RawMaterials/Material.g.cs b/libraries/MTConnect.NET-Common/Assets/RawMaterials/Material.g.cs index 44dc746cd..95233f234 100644 --- a/libraries/MTConnect.NET-Common/Assets/RawMaterials/Material.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/RawMaterials/Material.g.cs @@ -20,36 +20,43 @@ public class Material : IMaterial /// Unique identifier for the material. /// public string Id { get; set; } + /// /// Manufacturer's lot code of the material. /// public string Lot { get; set; } + /// /// Name of the material manufacturer. /// public string Manufacturer { get; set; } + /// /// Lot code of the raw feed stock for the material, from the feed stock manufacturer. /// public string ManufacturingCode { get; set; } + /// /// Manufacturing date of the material from the material manufacturer. /// public System.DateTime? ManufacturingDate { get; set; } + /// /// ASTM standard code that the material complies with. /// public string MaterialCode { get; set; } + /// /// Name of the material. Examples: `ULTM9085`, `ABS`, `4140`. /// public string Name { get; set; } + /// /// Type of material. Examples: `Metal`, `Polymer`, `Wood`, `4140`, `Recycled`, `Prestine` and `Used`. diff --git a/libraries/MTConnect.NET-Common/Assets/RawMaterials/RawMaterialAsset.g.cs b/libraries/MTConnect.NET-Common/Assets/RawMaterials/RawMaterialAsset.g.cs index 16e0017ac..47604be3e 100644 --- a/libraries/MTConnect.NET-Common/Assets/RawMaterials/RawMaterialAsset.g.cs +++ b/libraries/MTConnect.NET-Common/Assets/RawMaterials/RawMaterialAsset.g.cs @@ -20,76 +20,91 @@ public partial class RawMaterialAsset : Asset, IRawMaterialAsset /// Type of container holding the raw material. Examples: `Pallet`, `Canister`, `Cartridge`, `Tank`, `Bin`, `Roll`, and `Spool`. /// public string ContainerType { get; set; } + /// /// Dimension of material currently in raw material. /// public MTConnect.Millimeter3D CurrentDimension { get; set; } + /// /// Quantity of material currently in raw material. /// public int? CurrentQuantity { get; set; } + /// /// Amount of material currently in raw material. /// public double? CurrentVolume { get; set; } + /// /// Date raw material was first used. /// public System.DateTime? FirstUseDate { get; set; } + /// /// Form of the raw material. /// public MTConnect.Assets.RawMaterials.Form Form { get; set; } + /// /// Material has existing usable volume. /// public bool? HasMaterial { get; set; } + /// /// Dimension of material initially placed in raw material when manufactured. /// public MTConnect.Millimeter3D InitialDimension { get; set; } + /// /// Quantity of material initially placed in raw material when manufactured. /// public int? InitialQuantity { get; set; } + /// /// Amount of material initially placed in raw material when manufactured. /// public double? InitialVolume { get; set; } + /// /// Date raw material was last used. /// public System.DateTime? LastUseDate { get; set; } + /// /// Date the raw material was created. /// public System.DateTime? ManufacturingDate { get; set; } + /// /// Material used as the RawMaterial. /// public MTConnect.Assets.RawMaterials.IMaterial Material { get; set; } + /// /// Name of the raw material.Examples: `Container1` and `AcrylicContainer`. /// public string Name { get; set; } + /// /// ISO process type supported by this raw material. Examples include: `VAT_POLYMERIZATION`, `BINDER_JETTING`, `MATERIAL_EXTRUSION`, `MATERIAL_JETTING`, `SHEET_LAMINATION`, `POWDER_BED_FUSION` and `DIRECTED_ENERGY_DEPOSITION`. /// public string ProcessKind { get; set; } + /// /// Serial number of the raw material. diff --git a/libraries/MTConnect.NET-Common/Devices/AbstractDataItemRelationship.g.cs b/libraries/MTConnect.NET-Common/Devices/AbstractDataItemRelationship.g.cs index d4be03ddb..66dc9a359 100644 --- a/libraries/MTConnect.NET-Common/Devices/AbstractDataItemRelationship.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/AbstractDataItemRelationship.g.cs @@ -20,6 +20,7 @@ public abstract partial class AbstractDataItemRelationship : IAbstractDataItemRe /// Reference to the related entity's `id`. /// public string IdRef { get; set; } + /// /// Descriptive name associated with this AbstractDataItemRelationship. diff --git a/libraries/MTConnect.NET-Common/Devices/CellDefinition.g.cs b/libraries/MTConnect.NET-Common/Devices/CellDefinition.g.cs index 80b1fbc8b..77c61fa3c 100644 --- a/libraries/MTConnect.NET-Common/Devices/CellDefinition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/CellDefinition.g.cs @@ -20,26 +20,31 @@ public class CellDefinition : ICellDefinition /// Textual description for CellDefinition. /// public string Description { get; set; } + /// /// Unique identification of the Cell in the Definition. key. /// public string Key { get; set; } + /// /// Key. /// public string KeyType { get; set; } + /// /// SubType. See DataItem. /// public string SubType { get; set; } + /// /// Type. See DataItem Types. /// public string Type { get; set; } + /// /// Units. See Value Properties of DataItem. diff --git a/libraries/MTConnect.NET-Common/Devices/Component.g.cs b/libraries/MTConnect.NET-Common/Devices/Component.g.cs index 6e3d12a12..1722c6264 100644 --- a/libraries/MTConnect.NET-Common/Devices/Component.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Component.g.cs @@ -15,61 +15,82 @@ public partial class Component : IComponent /// public const string DescriptionText = "Logical or physical entity that provides a capability."; + /// + /// The OCL constraint bodies attached to this type in the source + /// SysML model, preserved verbatim so downstream consumers can + /// inspect the spec's raw validation rules at runtime. + /// + public static readonly string[] Rules = new[] + { + "val:MustHaveComponentOrDataItemOrReference\n a sh:NodeShape ;\n sh:message \"`Component` **MUST** have at least one of `Component`, `DataItem` or `Reference` entities.\" ;\n sh:targetClass mt:Component ;\n sh:or (\n [ sh:property [\n sh:path mt:hasComponent ;\n sh:minCount 1 ;\n sh:class mt:Component ;\n ] ]\n [ sh:property [\n sh:path mt:observes ;\n sh:minCount 1 ;\n sh:class mt:DataItem ;\n ] ]\n [ sh:property [\n sh:path mt:hasReference ;\n sh:minCount 1 ;\n sh:class mt:Reference ;\n ] ]\n ) ." + }; + /// /// Logical or physical entity that provides a capability. /// public System.Collections.Generic.IEnumerable Components { get; set; } + /// /// Functional part of a piece of equipment contained within a Component. /// public System.Collections.Generic.IEnumerable Compositions { get; set; } + /// /// Technical information about an entity describing its physical layout, functional characteristics, and relationships with other entities. /// public MTConnect.Devices.Configurations.IConfiguration Configuration { get; set; } + /// /// Specifies the CoordinateSystem for this Component and its children. /// public string CoordinateSystemIdRef { get; set; } + /// /// Descriptive content. /// public MTConnect.Devices.IDescription Description { get; set; } + /// /// Unique identifier for the Component. /// public string Id { get; set; } + /// /// Name of the Component.name **MUST** be unique for all child Component entities of a parent Component. /// public string Name { get; set; } + /// /// Common name associated with Component. /// public string NativeName { get; set; } + /// /// Pointer to information that is associated with another entity defined elsewhere in the MTConnectDevices entity for a piece of equipment. /// public System.Collections.Generic.IEnumerable References { get; set; } + /// /// Interval in milliseconds between the completion of the reading of the data associated with the Component until the beginning of the next sampling of that data.This information may be used by client software applications to understand how often information from a Component is expected to be refreshed.The refresh rate for data from all child Component entities will be thesampleInterval provided for the child Component. /// public double SampleInterval { get; set; } + /// /// SampleInterval. /// public double SampleRate { get; set; } + /// /// Universally unique identifier for the Component. diff --git a/libraries/MTConnect.NET-Common/Devices/Components/PowerComponent.g.cs b/libraries/MTConnect.NET-Common/Devices/Components/PowerComponent.g.cs index 0ca075c57..31084aee4 100644 --- a/libraries/MTConnect.NET-Common/Devices/Components/PowerComponent.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Components/PowerComponent.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.Components /// /// Power was **DEPRECATED** in *MTConnect Version 1.1* and was replaced by Availability data item type. /// + [System.Obsolete("Deprecated in v1.1")] public class PowerComponent : Component { /// diff --git a/libraries/MTConnect.NET-Common/Devices/Components/SpindleComponent.g.cs b/libraries/MTConnect.NET-Common/Devices/Components/SpindleComponent.g.cs index c33417c31..65a176a4c 100644 --- a/libraries/MTConnect.NET-Common/Devices/Components/SpindleComponent.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Components/SpindleComponent.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.Components /// /// Component that provides an axis of rotation for the purpose of rapidly rotating a part or a tool to provide sufficient surface speed for cutting operations.Spindle was **DEPRECATED** in *MTConnect Version 1.1* and was replaced by RotaryMode. /// + [System.Obsolete("Deprecated in v1.1")] public class SpindleComponent : Component { /// diff --git a/libraries/MTConnect.NET-Common/Devices/Components/ThermostatComponent.g.cs b/libraries/MTConnect.NET-Common/Devices/Components/ThermostatComponent.g.cs index 9e2719dd5..18a3208ad 100644 --- a/libraries/MTConnect.NET-Common/Devices/Components/ThermostatComponent.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Components/ThermostatComponent.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.Components /// /// Component composed of a sensor or an instrument that measures temperature.Thermostat was **DEPRECATED** in *MTConnect Version 1.2* and was replaced by Temperature. /// + [System.Obsolete("Deprecated in v1.2")] public class ThermostatComponent : Component { /// diff --git a/libraries/MTConnect.NET-Common/Devices/Components/VibrationComponent.g.cs b/libraries/MTConnect.NET-Common/Devices/Components/VibrationComponent.g.cs index cf48d2852..df6a18210 100644 --- a/libraries/MTConnect.NET-Common/Devices/Components/VibrationComponent.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Components/VibrationComponent.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.Components /// /// Component composed of a sensor or an instrument that measures the amount and/or frequency of vibration within a system.Vibration was **DEPRECATED** in *MTConnect Version 1.2* and was replaced by Displacement, Frequency etc. /// + [System.Obsolete("Deprecated in v1.2")] public class VibrationComponent : Component { /// diff --git a/libraries/MTConnect.NET-Common/Devices/Composition.g.cs b/libraries/MTConnect.NET-Common/Devices/Composition.g.cs index 7a6af5ca4..f7aeaeabd 100644 --- a/libraries/MTConnect.NET-Common/Devices/Composition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Composition.g.cs @@ -20,61 +20,73 @@ public partial class Composition : IComposition /// Technical information about an entity describing its physical layout, functional characteristics, and relationships with other entities. /// public MTConnect.Devices.Configurations.IConfiguration Configuration { get; set; } + /// /// Descriptive content. /// public MTConnect.Devices.IDescription Description { get; set; } + /// /// Unique identifier for the Composition element. /// public string Id { get; set; } + /// /// Name of the Composition element. /// public string Name { get; set; } + /// /// Type of Composition. /// public string Type { get; set; } + /// /// Universally unique identifier for the Composition. /// public string Uuid { get; set; } + /// /// Logical or physical entity that provides a capability. /// public System.Collections.Generic.IEnumerable Components { get; set; } + /// /// Functional part of a piece of equipment contained within a Component. /// public System.Collections.Generic.IEnumerable Compositions { get; set; } + /// /// Specifies the CoordinateSystem for this Component and its children. /// public string CoordinateSystemIdRef { get; set; } + /// /// Common name associated with Component. /// public string NativeName { get; set; } + /// /// Pointer to information that is associated with another entity defined elsewhere in the MTConnectDevices entity for a piece of equipment. /// public System.Collections.Generic.IEnumerable References { get; set; } + /// /// Interval in milliseconds between the completion of the reading of the data associated with the Component until the beginning of the next sampling of that data.This information may be used by client software applications to understand how often information from a Component is expected to be refreshed.The refresh rate for data from all child Component entities will be thesampleInterval provided for the child Component. /// public double SampleInterval { get; set; } + /// /// SampleInterval. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ActuatorComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ActuatorComposition.g.cs index 3e7db808a..919505e84 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ActuatorComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ActuatorComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that moves or controls a mechanical part of a piece of equipment.It takes energy usually provided by air, electric current, or liquid and converts the energy into some kind of motion. /// - public class ActuatorComposition : Composition + public class ActuatorComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/AmplifierComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/AmplifierComposition.g.cs index 403d0fc4b..fefb4e130 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/AmplifierComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/AmplifierComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of an electronic component or circuit that amplifies power, electric current, or voltage. /// - public class AmplifierComposition : Composition + public class AmplifierComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/BallscrewComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/BallscrewComposition.g.cs index 5b02be601..6181f04c3 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/BallscrewComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/BallscrewComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanical structure that transforms rotary motion into linear motion. /// - public class BallscrewComposition : Composition + public class BallscrewComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/BeltComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/BeltComposition.g.cs index c075fe390..ba6c96a85 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/BeltComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/BeltComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of an endless flexible band that transmits motion for a piece of equipment or conveys materials and objects. /// - public class BeltComposition : Composition + public class BeltComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/BrakeComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/BrakeComposition.g.cs index 83d3acc50..9312a9721 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/BrakeComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/BrakeComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that slows down or stops a moving object by the absorption or transfer of the energy of momentum, usually by means of friction, electrical force, or magnetic force. /// - public class BrakeComposition : Composition + public class BrakeComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ChainComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ChainComposition.g.cs index 0c041740e..473196113 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ChainComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ChainComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of an interconnected series of objects that band together and transmit motion for a piece of equipment or to convey materials and objects. /// - public class ChainComposition : Composition + public class ChainComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ChopperComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ChopperComposition.g.cs index 71e1c83e0..78452301f 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ChopperComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ChopperComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that breaks material into smaller pieces. /// - public class ChopperComposition : Composition + public class ChopperComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ChuckComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ChuckComposition.g.cs index 8020ba404..292f59abf 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ChuckComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ChuckComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that holds a part, stock material, or any other item in place. /// - public class ChuckComposition : Composition + public class ChuckComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ChuteComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ChuteComposition.g.cs index 50b3c326e..494155d38 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ChuteComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ChuteComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of an inclined channel that conveys material. /// - public class ChuteComposition : Composition + public class ChuteComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/CircuitBreakerComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/CircuitBreakerComposition.g.cs index c90a662e3..f79f531fc 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/CircuitBreakerComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/CircuitBreakerComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that interrupts an electric circuit. /// - public class CircuitBreakerComposition : Composition + public class CircuitBreakerComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ClampComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ClampComposition.g.cs index a3fc585f3..2f31b2a6b 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ClampComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ClampComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that strengthens, supports, or fastens objects in place. /// - public class ClampComposition : Composition + public class ClampComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/CompressorComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/CompressorComposition.g.cs index 617f65188..a4e33c0df 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/CompressorComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/CompressorComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a pump or other mechanism that reduces volume and increases pressure of gases in order to condense the gases to drive pneumatically powered pieces of equipment. /// - public class CompressorComposition : Composition + public class CompressorComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/CoolingTowerComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/CoolingTowerComposition.g.cs index 2f80863dd..97a9fb54d 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/CoolingTowerComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/CoolingTowerComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a heat exchange system that uses a fluid to transfer heat to the atmosphere. /// - public class CoolingTowerComposition : Composition + public class CoolingTowerComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/DoorComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/DoorComposition.g.cs index 792ecdc26..4d73349d5 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/DoorComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/DoorComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanical mechanism or closure that covers a physical access portal into a piece of equipment allowing or restricting access to other parts of the equipment. /// - public class DoorComposition : Composition + public class DoorComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/DrainComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/DrainComposition.g.cs index e0a53c4db..e0e00bec8 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/DrainComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/DrainComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that allows material to flow for the purpose of drainage from, for example, a vessel or tank. /// - public class DrainComposition : Composition + public class DrainComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/EncoderComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/EncoderComposition.g.cs index a72b24b95..aeb77c7fc 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/EncoderComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/EncoderComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that measures rotary position. /// - public class EncoderComposition : Composition + public class EncoderComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ExpiredPotComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ExpiredPotComposition.g.cs index 26d26a085..61990b20d 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ExpiredPotComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ExpiredPotComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Pot for a tool that is no longer usable for removal from a ToolMagazine or Turret. /// - public class ExpiredPotComposition : Composition + public class ExpiredPotComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ExposureUnitComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ExposureUnitComposition.g.cs index ac844f46a..63825d806 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ExposureUnitComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ExposureUnitComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that emits a type of radiation. /// - public class ExposureUnitComposition : Composition + public class ExposureUnitComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ExtrusionUnitComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ExtrusionUnitComposition.g.cs index 4d23cdc3d..0bbe03a80 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ExtrusionUnitComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ExtrusionUnitComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that dispenses liquid or powered materials. /// - public class ExtrusionUnitComposition : Composition + public class ExtrusionUnitComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/FanComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/FanComposition.g.cs index 923324701..4d69e4878 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/FanComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/FanComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that produces a current of air. /// - public class FanComposition : Composition + public class FanComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/FilterComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/FilterComposition.g.cs index 6dbe32589..08a01cc1a 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/FilterComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/FilterComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a substance or structure that allows liquids or gases to pass through to remove suspended impurities or to recover solids. /// - public class FilterComposition : Composition + public class FilterComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/GalvanomotorComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/GalvanomotorComposition.g.cs index 848d4d144..c0880c950 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/GalvanomotorComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/GalvanomotorComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of an electromechanical actuator that produces deflection of a beam of light or energy in response to electric current through its coil in a magnetic field. /// - public class GalvanomotorComposition : Composition + public class GalvanomotorComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/GripperComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/GripperComposition.g.cs index c6fc076c8..66b74797d 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/GripperComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/GripperComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that holds a part, stock material, or any other item in place. /// - public class GripperComposition : Composition + public class GripperComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/HopperComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/HopperComposition.g.cs index b292cc45d..c4b159502 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/HopperComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/HopperComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a chamber or bin that stores materials temporarily, typically being filled through the top and dispensed through the bottom. /// - public class HopperComposition : Composition + public class HopperComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/LinearPositionFeedbackComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/LinearPositionFeedbackComposition.g.cs index 50cd72e36..43cccd6a0 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/LinearPositionFeedbackComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/LinearPositionFeedbackComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that measures linear motion or position. /// - public class LinearPositionFeedbackComposition : Composition + public class LinearPositionFeedbackComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/MotorComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/MotorComposition.g.cs index ef31d7d9e..ee74e9a10 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/MotorComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/MotorComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that converts electrical, pneumatic, or hydraulic energy into mechanical energy. /// - public class MotorComposition : Composition + public class MotorComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/OilComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/OilComposition.g.cs index 2befde584..4df69186e 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/OilComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/OilComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a viscous liquid. /// - public class OilComposition : Composition + public class OilComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/PotComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/PotComposition.g.cs index d21d03ff8..04144b52e 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/PotComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/PotComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a tool storage location associated with a ToolMagazine or AutomaticToolChanger. /// - public class PotComposition : Composition + public class PotComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/PowerSupplyComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/PowerSupplyComposition.g.cs index 52c092b48..c13536f3b 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/PowerSupplyComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/PowerSupplyComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a unit that provides power to electric mechanisms. /// - public class PowerSupplyComposition : Composition + public class PowerSupplyComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/PulleyComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/PulleyComposition.g.cs index 9ce4da78f..923158012 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/PulleyComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/PulleyComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism or wheel that turns in a frame or block and serves to change the direction of or to transmit force. /// - public class PulleyComposition : Composition + public class PulleyComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/PumpComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/PumpComposition.g.cs index e50c2fd27..cc638a4bf 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/PumpComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/PumpComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of an apparatus that raises, drives, exhausts, or compresses fluids or gases by means of a piston, plunger, or set of rotating vanes. /// - public class PumpComposition : Composition + public class PumpComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ReelComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ReelComposition.g.cs index 75ff4fdc6..ed39a5d57 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ReelComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ReelComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a rotary storage unit for material. /// - public class ReelComposition : Composition + public class ReelComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/RemovalPotComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/RemovalPotComposition.g.cs index 5e9417ddf..45b412565 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/RemovalPotComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/RemovalPotComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Pot for a tool to be removed from a ToolMagazine or Turret to a location outside of the piece of equipment. /// - public class RemovalPotComposition : Composition + public class RemovalPotComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ReturnPotComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ReturnPotComposition.g.cs index cca48ca17..5a5b5f86a 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ReturnPotComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ReturnPotComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Pot for a tool removed from spindle or Turret and awaiting for return to a ToolMagazine. /// - public class ReturnPotComposition : Composition + public class ReturnPotComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/SensingElementComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/SensingElementComposition.g.cs index c1f11fb3d..0c6096895 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/SensingElementComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/SensingElementComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that provides a signal or measured value. /// - public class SensingElementComposition : Composition + public class SensingElementComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/SpreaderComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/SpreaderComposition.g.cs index cf64db12c..74b5e8765 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/SpreaderComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/SpreaderComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that flattens or spreads materials. /// - public class SpreaderComposition : Composition + public class SpreaderComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/StagingPotComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/StagingPotComposition.g.cs index d87c3b097..f268cbbbc 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/StagingPotComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/StagingPotComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Pot for a tool awaiting transfer to a ToolMagazine or Turret from outside of the piece of equipment. /// - public class StagingPotComposition : Composition + public class StagingPotComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/StationComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/StationComposition.g.cs index 8730ef04b..97d9828db 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/StationComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/StationComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a storage or mounting location for a tool associated with a Turret, GangToolBar, or ToolRack. /// - public class StationComposition : Composition + public class StationComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/StorageBatteryComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/StorageBatteryComposition.g.cs index 30de3d376..a7af41c15 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/StorageBatteryComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/StorageBatteryComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of one or more cells that converts chemical energy to electricity and serves as a source of power. /// - public class StorageBatteryComposition : Composition + public class StorageBatteryComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/SwitchComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/SwitchComposition.g.cs index e1423012d..fe19f9eea 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/SwitchComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/SwitchComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that turns on or off an electric current or makes or breaks a circuit. /// - public class SwitchComposition : Composition + public class SwitchComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/TableComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/TableComposition.g.cs index 152e5e87e..7fb267581 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/TableComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/TableComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a surface that holds an object or material. /// - public class TableComposition : Composition + public class TableComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/TankComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/TankComposition.g.cs index a7b03cde8..7e822a518 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/TankComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/TankComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a receptacle or container that holds material. /// - public class TankComposition : Composition + public class TankComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/TensionerComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/TensionerComposition.g.cs index 1aed45f8c..b3f39a646 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/TensionerComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/TensionerComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that provides or applies a stretch or strain to another mechanism. /// - public class TensionerComposition : Composition + public class TensionerComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/TransferArmComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/TransferArmComposition.g.cs index 869a74a71..d09ed0a2a 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/TransferArmComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/TransferArmComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that physically moves a tool from one location to another. /// - public class TransferArmComposition : Composition + public class TransferArmComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/TransferPotComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/TransferPotComposition.g.cs index 3c200ecdb..e45f3c161 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/TransferPotComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/TransferPotComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Pot for a tool awaiting transfer from a ToolMagazine to spindle or Turret. /// - public class TransferPotComposition : Composition + public class TransferPotComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/TransformerComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/TransformerComposition.g.cs index dcaefa0a7..82e150a45 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/TransformerComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/TransformerComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that transforms electric energy from a source to a secondary circuit. /// - public class TransformerComposition : Composition + public class TransformerComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/ValveComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/ValveComposition.g.cs index a9ca97bc7..ea31cfb7d 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/ValveComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/ValveComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a mechanism that halts or controls the flow of a liquid, gas, or other material through a passage, pipe, inlet, or outlet. /// - public class ValveComposition : Composition + public class ValveComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/VatComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/VatComposition.g.cs index 3fc0ed8d9..60a6bcfdd 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/VatComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/VatComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a container for liquid or powdered materials. /// - public class VatComposition : Composition + public class VatComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/WaterComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/WaterComposition.g.cs index 165da88ce..0216ce1d3 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/WaterComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/WaterComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a fluid. /// - public class WaterComposition : Composition + public class WaterComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/WireComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/WireComposition.g.cs index 29e4b8222..821c147a6 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/WireComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/WireComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of a string like piece or filament of relatively rigid or flexible material provided in a variety of diameters. /// - public class WireComposition : Composition + public class WireComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Compositions/WorkpieceComposition.g.cs b/libraries/MTConnect.NET-Common/Devices/Compositions/WorkpieceComposition.g.cs index 4e92c9266..58ae09961 100644 --- a/libraries/MTConnect.NET-Common/Devices/Compositions/WorkpieceComposition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Compositions/WorkpieceComposition.g.cs @@ -8,7 +8,7 @@ namespace MTConnect.Devices.Compositions /// /// Composition composed of an object or material on which a form of work is performed. /// - public class WorkpieceComposition : Composition + public class WorkpieceComposition : Composition { /// /// The MTConnect type value that identifies this Composition. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/AlarmLimits.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/AlarmLimits.g.cs index a993c11ac..d07f1e118 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/AlarmLimits.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/AlarmLimits.g.cs @@ -20,16 +20,19 @@ public class AlarmLimits : IAlarmLimits /// Lower conformance boundary for a variable.> Note: immediate concern or action may be required. /// public double? LowerLimit { get; set; } + /// /// Lower boundary indicating increased concern and supervision may be required. /// public double? LowerWarning { get; set; } + /// /// Upper conformance boundary for a variable.> Note: immediate concern or action may be required. /// public double? UpperLimit { get; set; } + /// /// Upper boundary indicating increased concern and supervision may be required. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/AssetRelationship.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/AssetRelationship.g.cs index d72a7b347..bad1449d1 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/AssetRelationship.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/AssetRelationship.g.cs @@ -20,11 +20,13 @@ public class AssetRelationship : ConfigurationRelationship, IAssetRelationship /// Uuid of the related Asset. /// public string AssetIdRef { get; set; } + /// /// Type of Asset being referenced. /// public string AssetType { get; set; } + /// /// URI reference to the associated Asset. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/Axis.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/Axis.g.cs index 4c3a8f29c..b0694234b 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/Axis.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/Axis.g.cs @@ -15,6 +15,16 @@ public class Axis : AbstractAxis, IAxis /// public new const string DescriptionText = "Axis along or around which the Component moves relative to a coordinate system."; + /// + /// The OCL constraint bodies attached to this type in the source + /// SysML model, preserved verbatim so downstream consumers can + /// inspect the spec's raw validation rules at runtime. + /// + public static readonly string[] Rules = new[] + { + "val:AxisValueMustBeUnitVector\n a sh:NodeShape ;\n sh:message \"Axis value must be a unit vector.\" ;\n sh:targetClass mt:Axis ;\n sh:sparql [\n a sh:SPARQLConstraint ;\n sh:message \"'value' property must form a unit vector: sqrt(x^2 + y^2 + z^2) = 1.\" ;\n sh:select \"\"\"\n SELECT $this\n WHERE {\n $this mt:value ?vec .\n ?vec mt:x ?x ; mt:y ?y ; mt:z ?z .\n FILTER ( ABS( SQRT((?x*?x) + (?y*?y) + (?z*?z)) - 1.0 ) > 1e-6 )\n }\n \"\"\" ;\n ] .\n" + }; + /// /// diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/AxisDataSet.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/AxisDataSet.g.cs index 6b51e9676..927781f0f 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/AxisDataSet.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/AxisDataSet.g.cs @@ -20,11 +20,13 @@ public class AxisDataSet : AbstractAxis, IAxisDataSet, IDataSet /// X-component of Axis. /// public double X { get; set; } + /// /// Y-component of Axis. /// public double Y { get; set; } + /// /// Z-component of Axis. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/Channel.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/Channel.g.cs index b21aa10c9..8f0a3409a 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/Channel.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/Channel.g.cs @@ -20,26 +20,31 @@ public class Channel : IChannel /// Date upon which the sensor unit was last calibrated to the sensor element. /// public System.DateTime? CalibrationDate { get; set; } + /// /// The initials of the person verifying the validity of the calibration data. /// public string CalibrationInitials { get; set; } + /// /// Textual description for Channel. /// public string Description { get; set; } + /// /// Name of the specific sensing element. /// public string Name { get; set; } + /// /// Date upon which the sensor element is next scheduled to be calibrated with the sensor unit. /// public System.DateTime? NextCalibrationDate { get; set; } + /// /// Unique identifier that will only refer to a specific sensing element. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/Configuration.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/Configuration.g.cs index 1d8be3109..9296e1f9a 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/Configuration.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/Configuration.g.cs @@ -20,36 +20,43 @@ public class Configuration : IConfiguration /// Reference system that associates a unique set of n parameters with each point in an n-dimensional space. ISO 10303-218:2004 /// public System.Collections.Generic.IEnumerable CoordinateSystems { get; set; } + /// /// Reference to a file containing an image of the Component. /// public System.Collections.Generic.IEnumerable ImageFiles { get; set; } + /// /// Movement of the component relative to a coordinate system. /// public MTConnect.Devices.Configurations.IMotion Motion { get; set; } + /// /// Potential energy sources for the Component. /// public MTConnect.Devices.Configurations.IPowerSource PowerSource { get; set; } + /// /// Association between two pieces of equipment or assets that may function independently but together perform a manufacturing operation. /// public System.Collections.Generic.IEnumerable Relationships { get; set; } + /// /// Configuration for a Sensor. /// public MTConnect.Devices.Configurations.ISensorConfiguration SensorConfiguration { get; set; } + /// /// References to a file with the three-dimensional geometry of the Component or Composition. /// public MTConnect.Devices.Configurations.ISolidModel SolidModel { get; set; } + /// /// Design characteristics for a piece of equipment. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/ConfigurationRelationship.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/ConfigurationRelationship.g.cs index dda5933bf..175cf2b58 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/ConfigurationRelationship.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/ConfigurationRelationship.g.cs @@ -20,16 +20,19 @@ public abstract class ConfigurationRelationship : IConfigurationRelationship /// Defines whether the services or functions provided by the associated piece of equipment is required for the operation of this piece of equipment. /// public MTConnect.Devices.Configurations.CriticalityType? Criticality { get; set; } + /// /// Unique identifier for this ConfigurationRelationship. /// public string Id { get; set; } + /// /// Name associated with this ConfigurationRelationship. /// public string Name { get; set; } + /// /// Defines the authority that this piece of equipment has relative to the associated piece of equipment. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/ControlLimits.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/ControlLimits.g.cs index 3f20c7e94..241424c7b 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/ControlLimits.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/ControlLimits.g.cs @@ -20,21 +20,25 @@ public class ControlLimits : IControlLimits /// Lower conformance boundary for a variable.> Note: immediate concern or action may be required. /// public double? LowerLimit { get; set; } + /// /// Lower boundary indicating increased concern and supervision may be required. /// public double? LowerWarning { get; set; } + /// /// Numeric target or expected value. /// public double? Nominal { get; set; } + /// /// Upper conformance boundary for a variable.> Note: immediate concern or action may be required. /// public double? UpperLimit { get; set; } + /// /// Upper boundary indicating increased concern and supervision may be required. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/CoordinateSystem.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/CoordinateSystem.g.cs index 692cf1f60..a80f0ee2f 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/CoordinateSystem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/CoordinateSystem.g.cs @@ -15,46 +15,64 @@ public class CoordinateSystem : ICoordinateSystem /// public const string DescriptionText = "Reference system that associates a unique set of n parameters with each point in an n-dimensional space. ISO 10303-218:2004"; + /// + /// The OCL constraint bodies attached to this type in the source + /// SysML model, preserved verbatim so downstream consumers can + /// inspect the spec's raw validation rules at runtime. + /// + public static readonly string[] Rules = new[] + { + "val:CoordinateSystemOriginOrTransformationExclusiveOptional\n a sh:NodeShape ;\n sh:message \"`CoordinateSystem` may have either an `Origin` or a `Transformation` but not both.\" ;\n sh:targetClass mt:CoordinateSystem ;\n\n sh:property [\n sh:path mt:hasOrigin ;\n sh:maxCount 1 ;\n sh:class mt:Origin ;\n ] ;\n\n sh:property [\n sh:path mt:hasTransformation ;\n sh:maxCount 1 ;\n sh:class mt:Transformation ;\n ] ;\n sh:sparql [\n a sh:SPARQLConstraint ;\n sh:select \"\"\"\n SELECT $this\n WHERE {\n OPTIONAL { $this mt:hasOrigin ?origin . }\n OPTIONAL { $this mt:hasTransformation ?trans . }\n FILTER (BOUND(?origin) && BOUND(?trans))\n }\n \"\"\" ;\n ] ." + }; + /// /// Natural language description of the CoordinateSystem. /// public string Description { get; set; } + /// /// Unique identifier for the coordinate system. /// public string Id { get; set; } + /// /// Name of the coordinate system. /// public string Name { get; set; } + /// /// Manufacturer's name or users name for the coordinate system. /// public string NativeName { get; set; } + /// /// Coordinates of the origin position of a coordinate system. /// public MTConnect.Devices.Configurations.IAbstractOrigin Origin { get; set; } + /// /// Id. /// public string ParentIdRef { get; set; } + /// /// Process of transforming to the origin position of the coordinate system from a parent coordinate system using Translation and Rotation. /// public MTConnect.Devices.Configurations.ITransformation Transformation { get; set; } + /// /// Type of coordinate system. /// public MTConnect.Devices.Configurations.CoordinateSystemType Type { get; set; } + /// /// UUID for the coordinate system. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/DeviceRelationship.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/DeviceRelationship.g.cs index 20eecd55c..5d9993567 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/DeviceRelationship.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/DeviceRelationship.g.cs @@ -20,16 +20,19 @@ public class DeviceRelationship : ConfigurationRelationship, IDeviceRelationship /// Uuid of the associated piece of equipment. /// public string DeviceUuidRef { get; set; } + /// /// URI identifying the agent that is publishing information for the associated piece of equipment. /// public string Href { get; set; } + /// /// Defines the services or capabilities that the referenced piece of equipment provides relative to this piece of equipment. /// public MTConnect.Devices.Configurations.RoleType? Role { get; set; } + /// /// `xlink:type`**MUST** have a fixed value of `locator` as defined in W3C XLink 1.1 https://www.w3.org/TR/xlink11/. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/IRelationship.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/IRelationship.g.cs deleted file mode 100644 index c70512669..000000000 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/IRelationship.g.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. -// TrakHound Inc. licenses this file to you under the MIT license. - -namespace MTConnect.Devices.Configurations -{ - /// - /// Association between two pieces of equipment that function independently but together perform a manufacturing operation. - /// - public interface IRelationship - { - /// - /// Defines whether the services or functions provided by the associated piece of equipment is required for the operation of this piece of equipment. - /// - MTConnect.Devices.Configurations.CriticalityType Criticality { get; } - - /// - /// Unique identifier for this ConfigurationRelationship. - /// - string Id { get; } - - /// - /// Name associated with this ConfigurationRelationship. - /// - string Name { get; } - - /// - /// Defines the authority that this piece of equipment has relative to the associated piece of equipment. - /// - MTConnect.Devices.Configurations.RelationshipType Type { get; } - } -} \ No newline at end of file diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/ImageFile.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/ImageFile.g.cs index 276c2ae40..62f3f3e25 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/ImageFile.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/ImageFile.g.cs @@ -20,16 +20,19 @@ public class ImageFile : IImageFile /// URL giving the location of the image file. /// public string Href { get; set; } + /// /// Unique identifier of the image file. /// public string Id { get; set; } + /// /// Mime type of the image file. /// public string MediaType { get; set; } + /// /// Description of the image file. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/Motion.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/Motion.g.cs index 8689cd1bd..d5297c5a9 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/Motion.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/Motion.g.cs @@ -20,41 +20,49 @@ public class Motion : IMotion /// Describes if this component is actuated directly or indirectly as a result of other motion. /// public MTConnect.Devices.Configurations.MotionActuationType Actuation { get; set; } + /// /// Axis along or around which the Component moves relative to a coordinate system. /// public MTConnect.Devices.Configurations.IAbstractAxis Axis { get; set; } + /// /// Coordinate system within which the kinematic motion occurs. /// public string CoordinateSystemIdRef { get; set; } + /// /// Textual description for Motion. /// public string Description { get; set; } + /// /// Unique identifier for this element. /// public string Id { get; set; } + /// /// Coordinates of the origin position of a coordinate system. /// public MTConnect.Devices.Configurations.IAbstractOrigin Origin { get; set; } + /// /// Id.The kinematic chain connects all components using the parent relations. All motion is connected to the motion of the parent. The first node in the chain will not have a parent. /// public string ParentIdRef { get; set; } + /// /// Process of transforming to the origin position of the coordinate system from a parent coordinate system using Translation and Rotation. /// public MTConnect.Devices.Configurations.ITransformation Transformation { get; set; } + /// /// Type of motion. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/OriginDataSet.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/OriginDataSet.g.cs index 8648a4ccb..e0779b41c 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/OriginDataSet.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/OriginDataSet.g.cs @@ -20,11 +20,13 @@ public class OriginDataSet : AbstractOrigin, IOriginDataSet, IDataSet /// X-coordinate. /// public string X { get; set; } + /// /// Y-coordinate. /// public string Y { get; set; } + /// /// X-coordinate. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/PowerSource.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/PowerSource.g.cs index 977f3cba6..12ae371bf 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/PowerSource.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/PowerSource.g.cs @@ -20,21 +20,25 @@ public class PowerSource : IPowerSource /// Reference to the Component providing observations about the power source. /// public string ComponentIdRef { get; set; } + /// /// Unique identifier for the power source. /// public string Id { get; set; } + /// /// Optional precedence for a given power source. /// public int Order { get; set; } + /// /// Type of the power source. /// public MTConnect.Devices.Configurations.PowerSourceType Type { get; set; } + /// /// Name of the power source. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/ProcessSpecification.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/ProcessSpecification.g.cs index adb16849a..58016d448 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/ProcessSpecification.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/ProcessSpecification.g.cs @@ -20,11 +20,13 @@ public class ProcessSpecification : Specification, IProcessSpecification /// Set of limits that is used to trigger warning or alarm indicators. /// public MTConnect.Devices.Configurations.IAlarmLimits AlarmLimits { get; set; } + /// /// Set of limits that is used to indicate whether a process variable is stable and in control. /// public MTConnect.Devices.Configurations.IControlLimits ControlLimits { get; set; } + /// /// Set of limits that define a range of values designating acceptable performance for a variable. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/RotationDataSet.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/RotationDataSet.g.cs index 3a5ecb0fd..faf57eb80 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/RotationDataSet.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/RotationDataSet.g.cs @@ -20,11 +20,13 @@ public class RotationDataSet : AbstractRotation, IRotationDataSet, IDataSet /// Rotation about X axis. /// public string A { get; set; } + /// /// Rotation about Y axis. /// public string B { get; set; } + /// /// Rotation about Z axis. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/ScaleDataSet.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/ScaleDataSet.g.cs index 561b1db71..503a7d488 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/ScaleDataSet.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/ScaleDataSet.g.cs @@ -20,11 +20,13 @@ public class ScaleDataSet : AbstractScale, IScaleDataSet, IDataSet /// Multiplier for X axis. /// public double X { get; set; } + /// /// Multiplier for Y axis. /// public double Y { get; set; } + /// /// Multiplier for Z axis. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/SensorConfiguration.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/SensorConfiguration.g.cs index e5df6628d..06b575f68 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/SensorConfiguration.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/SensorConfiguration.g.cs @@ -20,21 +20,25 @@ public class SensorConfiguration : ISensorConfiguration /// Date upon which the sensor unit was last calibrated. /// public System.DateTime? CalibrationDate { get; set; } + /// /// The initials of the person verifying the validity of the calibration data. /// public string CalibrationInitials { get; set; } + /// /// Sensing element of a Sensor. /// public System.Collections.Generic.IEnumerable Channels { get; set; } + /// /// Version number for the sensor unit as specified by the manufacturer. /// public string FirmwareVersion { get; set; } + /// /// Date upon which the sensor unit is next scheduled to be calibrated. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/SolidModel.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/SolidModel.g.cs index b55330026..7f1e2bc59 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/SolidModel.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/SolidModel.g.cs @@ -20,46 +20,55 @@ public class SolidModel : ISolidModel /// Reference to the coordinate system for this SolidModel. /// public string CoordinateSystemIdRef { get; set; } + /// /// URL giving the location of the SolidModel. solidModelIdRef is used.href is of type `xlink:href` from the W3C XLink specification. /// public string Href { get; set; } + /// /// Unique identifier for this element. /// public string Id { get; set; } + /// /// SolidModelIdRef **MUST** be given. > Note: `Item` defined in ASME Y14.100 - A nonspecific term used to denote any unit or product, including materials, parts, assemblies, equipment, accessories, and computer software. /// public string ItemRef { get; set; } + /// /// Format of the referenced document. /// public MTConnect.Devices.Configurations.MediaType MediaType { get; set; } + /// /// NativeUnits. See DataItem. /// public string NativeUnits { get; set; } + /// /// Either a single multiplier applied to all three dimensions or a three space multiplier given in the X, Y, and Z dimensions in the coordinate system used for the SolidModel. /// public MTConnect.Devices.Configurations.IAbstractScale Scale { get; set; } + /// /// Associated model file if an item reference is used. /// public string SolidModelIdRef { get; set; } + /// /// Process of transforming to the origin position of the coordinate system from a parent coordinate system using Translation and Rotation. /// public MTConnect.Devices.Configurations.ITransformation Transformation { get; set; } + /// /// Units. See DataItem. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/Specification.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/Specification.g.cs index 611148668..bcfa8555a 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/Specification.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/Specification.g.cs @@ -20,76 +20,91 @@ public class Specification : ISpecification /// Id associated with this entity. /// public string CompositionIdRef { get; set; } + /// /// References the CoordinateSystem for geometric Specification elements. /// public string CoordinateSystemIdRef { get; set; } + /// /// Id associated with this entity. /// public string DataItemIdRef { get; set; } + /// /// Unique identifier for this Specification. /// public string Id { get; set; } + /// /// Lower conformance boundary for a variable.> Note: immediate concern or action may be required. /// public double? LowerLimit { get; set; } + /// /// Lower boundary indicating increased concern and supervision may be required. /// public double? LowerWarning { get; set; } + /// /// Numeric upper constraint. /// public double? Maximum { get; set; } + /// /// Numeric lower constraint. /// public double? Minimum { get; set; } + /// /// Name provides additional meaning and differentiates between Specification entities. /// public string Name { get; set; } + /// /// Numeric target or expected value. /// public double? Nominal { get; set; } + /// /// Reference to the creator of the Specification. /// public MTConnect.Devices.Configurations.Originator Originator { get; set; } + /// /// SubType. See DataItem. /// public string SubType { get; set; } + /// /// Type. See DataItem Types. /// public string Type { get; set; } + /// /// Units. See DataItem. /// public string Units { get; set; } + /// /// Upper conformance boundary for a variable.> Note: immediate concern or action may be required. /// public double? UpperLimit { get; set; } + /// /// Upper boundary indicating increased concern and supervision may be required. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/SpecificationLimits.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/SpecificationLimits.g.cs index d348eabef..f36d7dd27 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/SpecificationLimits.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/SpecificationLimits.g.cs @@ -20,11 +20,13 @@ public class SpecificationLimits : ISpecificationLimits /// Lower conformance boundary for a variable.> Note: immediate concern or action may be required. /// public double? LowerLimit { get; set; } + /// /// Numeric target or expected value. /// public double? Nominal { get; set; } + /// /// Upper conformance boundary for a variable.> Note: immediate concern or action may be required. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/Transformation.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/Transformation.g.cs index ce53a868a..bab1e605e 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/Transformation.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/Transformation.g.cs @@ -15,11 +15,22 @@ public class Transformation : ITransformation /// public const string DescriptionText = "Process of transforming to the origin position of the coordinate system from a parent coordinate system using Translation and Rotation."; + /// + /// The OCL constraint bodies attached to this type in the source + /// SysML model, preserved verbatim so downstream consumers can + /// inspect the spec's raw validation rules at runtime. + /// + public static readonly string[] Rules = new[] + { + "val:TransformationMustHaveRotationOrTranslation\n a sh:NodeShape ;\n sh:message \"`Transformation` MUST have at least one of `Rotation` or `Translation` defined, and neither can be multiply defined.\" ;\n sh:targetClass mt:Transformation ;\n\n sh:property [\n sh:path mt:hasRotation ;\n sh:maxCount 1 ;\n sh:class mt:Rotation ;\n ] ;\n sh:property [\n sh:path mt:hasTranslation ;\n sh:maxCount 1 ;\n sh:class mt:Translation ;\n ] ;\n\n sh:or (\n [ sh:property [\n sh:path mt:hasRotation ;\n sh:minCount 1 ;\n ] ]\n [ sh:property [\n sh:path mt:hasTranslation ;\n sh:minCount 1 ;\n ] ]\n ) ." + }; + /// /// Rotations about X, Y, and Z axes are expressed in A, B, and C respectively within a 3-dimensional vector. /// public MTConnect.Devices.Configurations.IAbstractRotation Rotation { get; set; } + /// /// Translations along X, Y, and Z axes are expressed as x,y, and z respectively within a 3-dimensional vector. diff --git a/libraries/MTConnect.NET-Common/Devices/Configurations/TranslationDataSet.g.cs b/libraries/MTConnect.NET-Common/Devices/Configurations/TranslationDataSet.g.cs index 1291d23be..452c693cc 100644 --- a/libraries/MTConnect.NET-Common/Devices/Configurations/TranslationDataSet.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Configurations/TranslationDataSet.g.cs @@ -20,11 +20,13 @@ public class TranslationDataSet : AbstractTranslation, ITranslationDataSet, IDat /// Translation along X axis. /// public string X { get; set; } + /// /// Translation along Y axis. /// public string Y { get; set; } + /// /// Translation along Z axis. diff --git a/libraries/MTConnect.NET-Common/Devices/Constraints.g.cs b/libraries/MTConnect.NET-Common/Devices/Constraints.g.cs index 1653e7817..d28ada396 100644 --- a/libraries/MTConnect.NET-Common/Devices/Constraints.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Constraints.g.cs @@ -20,21 +20,25 @@ public class Constraints : IConstraints /// Provides a means to control when an agent records updated information for a DataItem. /// public MTConnect.Devices.IFilter Filter { get; set; } + /// /// Numeric upper constraint.If the data reported for a data item is a range of numeric values, the expected value reported **MAY** be described with an upper limit defined by this constraint. /// public double? Maximum { get; set; } + /// /// Numeric lower constraint.If the data reported for a data item is a range of numeric values, the expected value reported **MAY** be described with a lower limit defined by this constraint. /// public double? Minimum { get; set; } + /// /// Numeric target or expected value. /// public double? Nominal { get; set; } + /// /// Single data value that is expected to be reported for a DataItem.Value **MUST NOT** be used in conjunction with any other Constraint elements. diff --git a/libraries/MTConnect.NET-Common/Devices/DataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItem.g.cs index f6e8a6de1..f9ac49c72 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItem.g.cs @@ -15,116 +15,149 @@ public partial class DataItem : IDataItem /// public const string DescriptionText = "Information reported about a piece of equipment."; + /// + /// The OCL constraint bodies attached to this type in the source + /// SysML model, preserved verbatim so downstream consumers can + /// inspect the spec's raw validation rules at runtime. + /// + public static readonly string[] Rules = new[] + { + "id->size() = 1 and\n(self.oclAsType(DataItems::\"DataItem Types\"::Event).type->size() = 1 or\nself.oclAsType(DataItems::\"DataItem Types\"::Sample).type->size() = 1 or\nself.oclAsType(DataItems::\"DataItem Types\"::Condition).type->size() = 1\n) and\n(self.oclAsType(DataItems::\"DataItem Types\"::Event).category->size() = 1 or\nself.oclAsType(DataItems::\"DataItem Types\"::Sample).category->size() = 1 or\nself.oclAsType(DataItems::\"DataItem Types\"::Condition).category->size() = 1\n)", + "self.oclAsType(DataItems::\"DataItem Types\"::Event).category = DataTypes::CategoryEnum::EVENT or \nself.oclAsType(DataItems::\"DataItem Types\"::Sample).category = DataTypes::CategoryEnum::SAMPLE or\nself.oclAsType(DataItems::\"DataItem Types\"::Condition).category = DataTypes::CategoryEnum::CONDITION" + }; + /// /// Specifies the kind of information provided by a data item. /// public MTConnect.Devices.DataItemCategory Category { get; set; } + /// /// Identifier attribute of the Composition that the reported data is most closely associated. /// public string CompositionId { get; set; } + /// /// Organize a set of expected values that can be reported for a DataItem. /// public MTConnect.Devices.IConstraints Constraints { get; set; } + /// /// For measured values relative to a coordinate system like Position, the coordinate system used may be reported.coordinateSystemIdRef. /// public MTConnect.Devices.DataItemCoordinateSystem CoordinateSystem { get; set; } + /// /// Associated CoordinateSystem context for the DataItem. /// public string CoordinateSystemIdRef { get; set; } + /// /// Representation is either `DATA_SET` or `TABLE`. /// public MTConnect.Devices.IDataItemDefinition Definition { get; set; } + /// /// Indication signifying whether each value reported for the Observation is significant and whether duplicate values are to be suppressed.discrete, the default value **MUST** be `false`. /// public bool Discrete { get; set; } + /// /// Provides a means to control when an agent records updated information for a DataItem. /// public System.Collections.Generic.IEnumerable Filters { get; set; } + /// /// Unique identifier for this data item. /// public string Id { get; set; } + /// /// Starting value for a DataItem as well as the value to be set for the DataItem after a reset event. /// public string InitialValue { get; set; } + /// /// Name of the data item. /// public string Name { get; set; } + /// /// Used to convert the reported value to represent the original measured value. /// public int NativeScale { get; set; } + /// /// Native units of measurement for the reported value of the data item. /// public string NativeUnits { get; set; } + /// /// Association between a DataItem and another entity. /// public System.Collections.Generic.IEnumerable Relationships { get; set; } + /// /// Description of a means to interpret data consisting of multiple data points or samples reported as a single value. representation is not specified, it **MUST** be determined to be `VALUE`. /// public MTConnect.Devices.DataItemRepresentation Representation { get; set; } + /// /// Type of event that may cause a reset to occur. /// public MTConnect.Devices.DataItemResetTrigger? ResetTrigger { get; set; } + /// /// Rate at which successive samples of a data item are recorded by a piece of equipment. /// public double SampleRate { get; set; } + /// /// Number of significant digits in the reported value. /// public int? SignificantDigits { get; set; } + /// /// Identifies the Component, DataItem, or Composition from which a measured value originates. /// public MTConnect.Devices.ISource Source { get; set; } + /// /// Type of statistical calculation performed on a series of data samples to provide the reported data value. /// public MTConnect.Devices.DataItemStatistic? Statistic { get; set; } + /// /// Type. /// public string SubType { get; set; } + /// /// Type of data being measured. See DataItem Types. /// public string Type { get; set; } + /// /// Unit of measurement for the reported value of the data item. diff --git a/libraries/MTConnect.NET-Common/Devices/DataItemDefinition.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItemDefinition.g.cs index 1d2010f68..226b84540 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItemDefinition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItemDefinition.g.cs @@ -20,11 +20,13 @@ public class DataItemDefinition : IDataItemDefinition /// Semantic definition of a Cell. /// public System.Collections.Generic.IEnumerable CellDefinitions { get; set; } + /// /// Textual description for Definition. /// public string Description { get; set; } + /// /// Semantic definition of an Entry. diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/AlarmLimitDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/AlarmLimitDataItem.g.cs index 7ba12da36..b70f3d325 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/AlarmLimitDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/AlarmLimitDataItem.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.DataItems /// /// Set of limits used to trigger warning or alarm indicators.**DEPRECATED** in *Version 2.5*. Replaced by `ALARM_LIMITS`. /// + [System.Obsolete("Deprecated in v2.5")] public class AlarmLimitDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/AmperageDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/AmperageDataItem.g.cs index 3da1ff182..395d93460 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/AmperageDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/AmperageDataItem.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.DataItems /// /// Strength of electrical current.**DEPRECATED** in *Version 1.6*. Replaced by `AMPERAGE_AC` and `AMPERAGE_DC`. /// + [System.Obsolete("Deprecated in v1.6")] public class AmperageDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/CodeDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/CodeDataItem.g.cs index e51b5587e..de9e9328e 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/CodeDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/CodeDataItem.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.DataItems /// /// Programmatic code being executed.**DEPRECATED** in *Version 1.1*. /// + [System.Obsolete("Deprecated in v1.1")] public class CodeDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/ControlLimitDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/ControlLimitDataItem.g.cs index 6f549ad66..d6bbde4aa 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/ControlLimitDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/ControlLimitDataItem.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.DataItems /// /// Set of limits used to indicate whether a process variable is stable and in control.**DEPRECATED** in *Version 2.5*. Replaced by `CONTROL_LIMITS`. /// + [System.Obsolete("Deprecated in v2.5")] public class ControlLimitDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/GlobalPositionDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/GlobalPositionDataItem.g.cs index 4bf6851d8..29aacf6dc 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/GlobalPositionDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/GlobalPositionDataItem.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.DataItems /// /// Position in three-dimensional space.**DEPRECATED** in Version 1.1. /// + [System.Obsolete("Deprecated in v1.1")] public class GlobalPositionDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/LineDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/LineDataItem.g.cs index 61f6e3ca6..ff825ddb1 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/LineDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/LineDataItem.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.DataItems /// /// Current line of code being executed.**DEPRECATED** in *Version 1.4.0*. /// + [System.Obsolete("Deprecated in v1.4")] public class LineDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/PartNumberDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/PartNumberDataItem.g.cs index 56f49b341..4323479fe 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/PartNumberDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/PartNumberDataItem.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.DataItems /// /// Identifier of a part or product moving through the manufacturing process.**DEPRECATED** in *Version 1.7*. `PART_NUMBER` is now a `subType` of `PART_KIND_ID`. /// + [System.Obsolete("Deprecated in v1.7")] public class PartNumberDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/PowerStatusDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/PowerStatusDataItem.g.cs index 0c00fb1b8..941e2f58d 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/PowerStatusDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/PowerStatusDataItem.g.cs @@ -13,6 +13,7 @@ namespace MTConnect.Devices.DataItems /// /// Status of the Component.**DEPRECATED** in *Version 1.1.0*. /// + [System.Obsolete("Deprecated in v1.1")] public class PowerStatusDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/SpecificationLimitDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/SpecificationLimitDataItem.g.cs index 2e5734e50..8e39d0c70 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/SpecificationLimitDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/SpecificationLimitDataItem.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.DataItems /// /// Set of limits defining a range of values designating acceptable performance for a variable.**DEPRECATED** in *Version 2.5*. Replaced by `SPECIFICATION_LIMITS`. /// + [System.Obsolete("Deprecated in v2.5")] public class SpecificationLimitDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/SpindleSpeedDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/SpindleSpeedDataItem.g.cs index fd88d523b..4f5debbd0 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/SpindleSpeedDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/SpindleSpeedDataItem.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.DataItems /// /// Rotational speed of the rotary axis.**DEPRECATED** in *Version 1.2*. Replaced by `ROTARY_VELOCITY`. /// + [System.Obsolete("Deprecated in v1.2")] public class SpindleSpeedDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/ToolIdDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/ToolIdDataItem.g.cs index 133fe5c76..24c04c2b8 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/ToolIdDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/ToolIdDataItem.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.DataItems /// /// Identifier of the tool currently in use for a given `Path`.**DEPRECATED** in *Version 1.2.0*. See `TOOL_NUMBER`. /// + [System.Obsolete("Deprecated in v1.2")] public class ToolIdDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/DataItems/VoltageDataItem.g.cs b/libraries/MTConnect.NET-Common/Devices/DataItems/VoltageDataItem.g.cs index 4562f0f3c..30d84db32 100644 --- a/libraries/MTConnect.NET-Common/Devices/DataItems/VoltageDataItem.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/DataItems/VoltageDataItem.g.cs @@ -8,6 +8,7 @@ namespace MTConnect.Devices.DataItems /// /// Electrical potential between two points.**DEPRECATED** in *Version 1.6*. Replaced by `VOLTAGE_AC` and `VOLTAGE_DC`. /// + [System.Obsolete("Deprecated in v1.6")] public class VoltageDataItem : DataItem { /// diff --git a/libraries/MTConnect.NET-Common/Devices/Description.g.cs b/libraries/MTConnect.NET-Common/Devices/Description.g.cs index 7bfa4657d..5973a108b 100644 --- a/libraries/MTConnect.NET-Common/Devices/Description.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Description.g.cs @@ -20,21 +20,25 @@ public class Description : IDescription /// Name of the manufacturer of the physical or logical part of a piece of equipment represented by this element. /// public string Manufacturer { get; set; } + /// /// Model description of the physical part or logical function of a piece of equipment represented by this element. /// public string Model { get; set; } + /// /// Serial number associated with a piece of equipment. /// public string SerialNumber { get; set; } + /// /// Identifier where a manufacturing function takes place. /// public string Station { get; set; } + /// /// Description of the element. diff --git a/libraries/MTConnect.NET-Common/Devices/Device.g.cs b/libraries/MTConnect.NET-Common/Devices/Device.g.cs index 3d5eb9919..102b1e640 100644 --- a/libraries/MTConnect.NET-Common/Devices/Device.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Device.g.cs @@ -15,71 +15,95 @@ public partial class Device : IDevice /// public const string DescriptionText = "Component composed of a piece of equipment that produces observation about itself."; + /// + /// The OCL constraint bodies attached to this type in the source + /// SysML model, preserved verbatim so downstream consumers can + /// inspect the spec's raw validation rules at runtime. + /// + public static readonly string[] Rules = new[] + { + "Components::Devices::Device::allInstances()->iterate(device;devicecount:Real=0|\nif device.observes->size() >= 3\nthen \n if device.observes->iterate(av;avail:Real=0|if av.oclAsType(DataItems::\"DataItem Types\"::Event).type = DataTypes::EventEnum::AVAILABILITY then avail+1 else avail+0 endif) = 1\n then if device.observes->iterate(ac;assetc:Real=0|if ac.oclAsType(DataItems::\"DataItem Types\"::Event).type = DataTypes::EventEnum::ASSET_CHANGED then assetc+1 else assetc+0 endif) = 1\n then if device.observes->iterate(ar;assetr:Real=0|if ar.oclAsType(DataItems::\"DataItem Types\"::Event).type = DataTypes::EventEnum::ASSET_REMOVED then assetr+1 else assetr+0 endif) = 1\n then devicecount + 1\n else devicecount + 0\n endif\n else devicecount + 0\n endif\n else devicecount + 0\n endif\nelse devicecount + 0\nendif) = hasDevice->size()", + "Components::Devices::Device::allInstances()->iterate(device;devicecount:Real=0|\nif device.id->size() = 1 and \n device.name->size() = 1 and\n device.uuid->size() = 1 and\n (device.observes->size() > 0 or device.hasReference->size() > 0 or device.hasComponent->size() > 0) \nthen\n devicecount + 1\nelse\n devicecount + 0\nendif\n) = Components::Devices::Device::allInstances()->size()" + }; + /// /// Condensed message digest from a secure one-way hash function. FIPS PUB 180-4 /// public string Hash { get; set; } + /// /// MTConnect version of the Device Information Model used to configure the information to be published for a piece of equipment in an MTConnect Response Document. /// public System.Version MTConnectVersion { get; set; } + /// /// Name of an element or a piece of equipment. /// public string Name { get; set; } + /// /// Universally unique identifier for the element. /// public string Uuid { get; set; } + /// /// Logical or physical entity that provides a capability. /// public System.Collections.Generic.IEnumerable Components { get; set; } + /// /// Functional part of a piece of equipment contained within a Component. /// public System.Collections.Generic.IEnumerable Compositions { get; set; } + /// /// Technical information about an entity describing its physical layout, functional characteristics, and relationships with other entities. /// public MTConnect.Devices.Configurations.IConfiguration Configuration { get; set; } + /// /// Specifies the CoordinateSystem for this Component and its children. /// public string CoordinateSystemIdRef { get; set; } + /// /// Descriptive content. /// public MTConnect.Devices.IDescription Description { get; set; } + /// /// Unique identifier for the Component. /// public string Id { get; set; } + /// /// Common name associated with Component. /// public string NativeName { get; set; } + /// /// Pointer to information that is associated with another entity defined elsewhere in the MTConnectDevices entity for a piece of equipment. /// public System.Collections.Generic.IEnumerable References { get; set; } + /// /// Interval in milliseconds between the completion of the reading of the data associated with the Component until the beginning of the next sampling of that data.This information may be used by client software applications to understand how often information from a Component is expected to be refreshed.The refresh rate for data from all child Component entities will be thesampleInterval provided for the child Component. /// public double SampleInterval { get; set; } + /// /// SampleInterval. diff --git a/libraries/MTConnect.NET-Common/Devices/EntryDefinition.g.cs b/libraries/MTConnect.NET-Common/Devices/EntryDefinition.g.cs index 2b807d0ad..2a23a541f 100644 --- a/libraries/MTConnect.NET-Common/Devices/EntryDefinition.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/EntryDefinition.g.cs @@ -20,31 +20,37 @@ public class EntryDefinition : IEntryDefinition /// Semantic definition of a Cell. /// public System.Collections.Generic.IEnumerable CellDefinitions { get; set; } + /// /// Textual description for EntryDefinition. /// public string Description { get; set; } + /// /// Unique identification of the Entry in the Definition. key. /// public string Key { get; set; } + /// /// Key. /// public string KeyType { get; set; } + /// /// SubType. See DataItem. /// public string SubType { get; set; } + /// /// Type. See DataItem Types. /// public string Type { get; set; } + /// /// Units. See Value Properties of DataItem. diff --git a/libraries/MTConnect.NET-Common/Devices/Filter.g.cs b/libraries/MTConnect.NET-Common/Devices/Filter.g.cs index 672b82be2..413fe8927 100644 --- a/libraries/MTConnect.NET-Common/Devices/Filter.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Filter.g.cs @@ -20,6 +20,7 @@ public class Filter : IFilter /// Type of Filter. /// public MTConnect.Devices.DataItemFilterType Type { get; set; } + /// /// diff --git a/libraries/MTConnect.NET-Common/Devices/References/Reference.g.cs b/libraries/MTConnect.NET-Common/Devices/References/Reference.g.cs index 5242e059c..4ab619b18 100644 --- a/libraries/MTConnect.NET-Common/Devices/References/Reference.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/References/Reference.g.cs @@ -20,16 +20,19 @@ public abstract partial class Reference : IReference /// Id that contains the information to be associated with this entity. /// public string DataItemId { get; set; } + /// /// Pointer to the `id` of an entity that contains the information to be associated with this entity. /// public string IdRef { get; set; } + /// /// name of an element or a piece of equipment. /// public string Name { get; set; } + /// /// Id that contains the information to be associated with this entity. diff --git a/libraries/MTConnect.NET-Common/Devices/Source.g.cs b/libraries/MTConnect.NET-Common/Devices/Source.g.cs index 532862167..857d2c0d1 100644 --- a/libraries/MTConnect.NET-Common/Devices/Source.g.cs +++ b/libraries/MTConnect.NET-Common/Devices/Source.g.cs @@ -20,16 +20,19 @@ public class Source : ISource /// Identifier of the Component that represents the physical part of a piece of equipment where the data represented by the DataItem originated. /// public string ComponentId { get; set; } + /// /// Identifier of the Composition that represents the physical part of a piece of equipment where the data represented by the DataItem originated. /// public string CompositionId { get; set; } + /// /// Identifier of the DataItem that represents the originally measured value of the data referenced by this DataItem. /// public string DataItemId { get; set; } + /// /// Identifier of the source entity. diff --git a/libraries/MTConnect.NET-Common/Observations/Events/NetworkWireless.g.cs b/libraries/MTConnect.NET-Common/Observations/Events/NetworkWireless.g.cs deleted file mode 100644 index 395953e27..000000000 --- a/libraries/MTConnect.NET-Common/Observations/Events/NetworkWireless.g.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. -// TrakHound Inc. licenses this file to you under the MIT license. - -namespace MTConnect.Observations.Events -{ - /// - /// - /// - public enum NetworkWireless - { - /// - /// - /// - YES, - - /// - /// - /// - NO - } -} \ No newline at end of file diff --git a/libraries/MTConnect.NET-Common/Observations/Events/SensorStateDetect.g.cs b/libraries/MTConnect.NET-Common/Observations/Events/SensorStateDetect.g.cs deleted file mode 100644 index 19886904e..000000000 --- a/libraries/MTConnect.NET-Common/Observations/Events/SensorStateDetect.g.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2023 TrakHound Inc., All Rights Reserved. -// TrakHound Inc. licenses this file to you under the MIT license. - -namespace MTConnect.Observations.Events -{ - /// - /// - /// - public enum SensorStateDetect - { - /// - /// Activation state of the Composition is in an `ON` condition, it is operating, or it is powered. - /// - ON, - - /// - /// Activation state of the Composition is in an `OFF` condition, it is not operating, or it is not powered. - /// - OFF - } -} \ No newline at end of file diff --git a/libraries/MTConnect.NET-JSON-cppagent/Devices/JsonComponents.g.cs b/libraries/MTConnect.NET-JSON-cppagent/Devices/JsonComponents.g.cs index 96b82711a..3dd0cbb54 100644 --- a/libraries/MTConnect.NET-JSON-cppagent/Devices/JsonComponents.g.cs +++ b/libraries/MTConnect.NET-JSON-cppagent/Devices/JsonComponents.g.cs @@ -568,14 +568,6 @@ public class JsonComponents public IEnumerable Pot { get; set; } - /// - /// The set of Power components on the device. - /// Power was **DEPRECATED** in *MTConnect Version 1.1* and was replaced by Availability data item type. - /// - [JsonPropertyName("Power")] - public IEnumerable Power { get; set; } - - /// /// The set of PowerSupply components on the device. /// Leaf Component that provides power to electric mechanisms. @@ -712,14 +704,6 @@ public class JsonComponents public IEnumerable Sensor { get; set; } - /// - /// The set of Spindle components on the device. - /// Component that provides an axis of rotation for the purpose of rapidly rotating a part or a tool to provide sufficient surface speed for cutting operations.Spindle was **DEPRECATED** in *MTConnect Version 1.1* and was replaced by RotaryMode. - /// - [JsonPropertyName("Spindle")] - public IEnumerable Spindle { get; set; } - - /// /// The set of Spreader components on the device. /// Leaf Component that flattens or spreading materials. @@ -824,14 +808,6 @@ public class JsonComponents public IEnumerable Tensioner { get; set; } - /// - /// The set of Thermostat components on the device. - /// Component composed of a sensor or an instrument that measures temperature.Thermostat was **DEPRECATED** in *MTConnect Version 1.2* and was replaced by Temperature. - /// - [JsonPropertyName("Thermostat")] - public IEnumerable Thermostat { get; set; } - - /// /// The set of ToolHolder components on the device. /// System that securely interfaces a Component with a Device @@ -920,14 +896,6 @@ public class JsonComponents public IEnumerable Vat { get; set; } - /// - /// The set of Vibration components on the device. - /// Component composed of a sensor or an instrument that measures the amount and/or frequency of vibration within a system.Vibration was **DEPRECATED** in *MTConnect Version 1.2* and was replaced by Displacement, Frequency etc. - /// - [JsonPropertyName("Vibration")] - public IEnumerable Vibration { get; set; } - - /// /// The set of WasteDisposal components on the device. /// Auxiliary that removes manufacturing byproducts from a piece of equipment. @@ -1120,8 +1088,6 @@ public JsonComponents(IEnumerable components) Pot = GetComponents(components, PotComponent.TypeId); - Power = GetComponents(components, PowerComponent.TypeId); - PowerSupply = GetComponents(components, PowerSupplyComponent.TypeId); Pressure = GetComponents(components, PressureComponent.TypeId); @@ -1156,8 +1122,6 @@ public JsonComponents(IEnumerable components) Sensor = GetComponents(components, SensorComponent.TypeId); - Spindle = GetComponents(components, SpindleComponent.TypeId); - Spreader = GetComponents(components, SpreaderComponent.TypeId); StagingPot = GetComponents(components, StagingPotComponent.TypeId); @@ -1184,8 +1148,6 @@ public JsonComponents(IEnumerable components) Tensioner = GetComponents(components, TensionerComponent.TypeId); - Thermostat = GetComponents(components, ThermostatComponent.TypeId); - ToolHolder = GetComponents(components, ToolHolderComponent.TypeId); ToolingDelivery = GetComponents(components, ToolingDeliveryComponent.TypeId); @@ -1208,8 +1170,6 @@ public JsonComponents(IEnumerable components) Vat = GetComponents(components, VatComponent.TypeId); - Vibration = GetComponents(components, VibrationComponent.TypeId); - WasteDisposal = GetComponents(components, WasteDisposalComponent.TypeId); Water = GetComponents(components, WaterComponent.TypeId); @@ -1385,8 +1345,6 @@ public IEnumerable ToComponents() if (!Pot.IsNullOrEmpty()) foreach (var component in Pot) components.Add(component.ToComponent(PotComponent.TypeId)); - if (!Power.IsNullOrEmpty()) foreach (var component in Power) components.Add(component.ToComponent(PowerComponent.TypeId)); - if (!PowerSupply.IsNullOrEmpty()) foreach (var component in PowerSupply) components.Add(component.ToComponent(PowerSupplyComponent.TypeId)); if (!Pressure.IsNullOrEmpty()) foreach (var component in Pressure) components.Add(component.ToComponent(PressureComponent.TypeId)); @@ -1421,8 +1379,6 @@ public IEnumerable ToComponents() if (!Sensor.IsNullOrEmpty()) foreach (var component in Sensor) components.Add(component.ToComponent(SensorComponent.TypeId)); - if (!Spindle.IsNullOrEmpty()) foreach (var component in Spindle) components.Add(component.ToComponent(SpindleComponent.TypeId)); - if (!Spreader.IsNullOrEmpty()) foreach (var component in Spreader) components.Add(component.ToComponent(SpreaderComponent.TypeId)); if (!StagingPot.IsNullOrEmpty()) foreach (var component in StagingPot) components.Add(component.ToComponent(StagingPotComponent.TypeId)); @@ -1449,8 +1405,6 @@ public IEnumerable ToComponents() if (!Tensioner.IsNullOrEmpty()) foreach (var component in Tensioner) components.Add(component.ToComponent(TensionerComponent.TypeId)); - if (!Thermostat.IsNullOrEmpty()) foreach (var component in Thermostat) components.Add(component.ToComponent(ThermostatComponent.TypeId)); - if (!ToolHolder.IsNullOrEmpty()) foreach (var component in ToolHolder) components.Add(component.ToComponent(ToolHolderComponent.TypeId)); if (!ToolingDelivery.IsNullOrEmpty()) foreach (var component in ToolingDelivery) components.Add(component.ToComponent(ToolingDeliveryComponent.TypeId)); @@ -1473,8 +1427,6 @@ public IEnumerable ToComponents() if (!Vat.IsNullOrEmpty()) foreach (var component in Vat) components.Add(component.ToComponent(VatComponent.TypeId)); - if (!Vibration.IsNullOrEmpty()) foreach (var component in Vibration) components.Add(component.ToComponent(VibrationComponent.TypeId)); - if (!WasteDisposal.IsNullOrEmpty()) foreach (var component in WasteDisposal) components.Add(component.ToComponent(WasteDisposalComponent.TypeId)); if (!Water.IsNullOrEmpty()) foreach (var component in Water) components.Add(component.ToComponent(WaterComponent.TypeId)); diff --git a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonEvents.g.cs b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonEvents.g.cs index fa114e8d2..7bc4a3846 100644 --- a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonEvents.g.cs +++ b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonEvents.g.cs @@ -57,10 +57,6 @@ public List Observations if (!AlarmDataSet.IsNullOrEmpty()) foreach (var x in AlarmDataSet) l.Add(x.ToObservation(AlarmDataItem.TypeId)); if (!AlarmTable.IsNullOrEmpty()) foreach (var x in AlarmTable) l.Add(x.ToObservation(AlarmDataItem.TypeId)); - if (!AlarmLimit.IsNullOrEmpty()) foreach (var x in AlarmLimit) l.Add(x.ToObservation(AlarmLimitDataItem.TypeId)); - if (!AlarmLimitDataSet.IsNullOrEmpty()) foreach (var x in AlarmLimitDataSet) l.Add(x.ToObservation(AlarmLimitDataItem.TypeId)); - if (!AlarmLimitTable.IsNullOrEmpty()) foreach (var x in AlarmLimitTable) l.Add(x.ToObservation(AlarmLimitDataItem.TypeId)); - if (!AlarmLimits.IsNullOrEmpty()) foreach (var x in AlarmLimits) l.Add(x.ToObservation(AlarmLimitsDataItem.TypeId)); if (!AlarmLimitsDataSet.IsNullOrEmpty()) foreach (var x in AlarmLimitsDataSet) l.Add(x.ToObservation(AlarmLimitsDataItem.TypeId)); if (!AlarmLimitsTable.IsNullOrEmpty()) foreach (var x in AlarmLimitsTable) l.Add(x.ToObservation(AlarmLimitsDataItem.TypeId)); @@ -145,10 +141,6 @@ public List Observations if (!ClockTimeDataSet.IsNullOrEmpty()) foreach (var x in ClockTimeDataSet) l.Add(x.ToObservation(ClockTimeDataItem.TypeId)); if (!ClockTimeTable.IsNullOrEmpty()) foreach (var x in ClockTimeTable) l.Add(x.ToObservation(ClockTimeDataItem.TypeId)); - if (!Code.IsNullOrEmpty()) foreach (var x in Code) l.Add(x.ToObservation(CodeDataItem.TypeId)); - if (!CodeDataSet.IsNullOrEmpty()) foreach (var x in CodeDataSet) l.Add(x.ToObservation(CodeDataItem.TypeId)); - if (!CodeTable.IsNullOrEmpty()) foreach (var x in CodeTable) l.Add(x.ToObservation(CodeDataItem.TypeId)); - if (!ComponentData.IsNullOrEmpty()) foreach (var x in ComponentData) l.Add(x.ToObservation(ComponentDataDataItem.TypeId)); if (!ComponentDataDataSet.IsNullOrEmpty()) foreach (var x in ComponentDataDataSet) l.Add(x.ToObservation(ComponentDataDataItem.TypeId)); if (!ComponentDataTable.IsNullOrEmpty()) foreach (var x in ComponentDataTable) l.Add(x.ToObservation(ComponentDataDataItem.TypeId)); @@ -161,10 +153,6 @@ public List Observations if (!ConnectionStatusDataSet.IsNullOrEmpty()) foreach (var x in ConnectionStatusDataSet) l.Add(x.ToObservation(ConnectionStatusDataItem.TypeId)); if (!ConnectionStatusTable.IsNullOrEmpty()) foreach (var x in ConnectionStatusTable) l.Add(x.ToObservation(ConnectionStatusDataItem.TypeId)); - if (!ControlLimit.IsNullOrEmpty()) foreach (var x in ControlLimit) l.Add(x.ToObservation(ControlLimitDataItem.TypeId)); - if (!ControlLimitDataSet.IsNullOrEmpty()) foreach (var x in ControlLimitDataSet) l.Add(x.ToObservation(ControlLimitDataItem.TypeId)); - if (!ControlLimitTable.IsNullOrEmpty()) foreach (var x in ControlLimitTable) l.Add(x.ToObservation(ControlLimitDataItem.TypeId)); - if (!ControlLimits.IsNullOrEmpty()) foreach (var x in ControlLimits) l.Add(x.ToObservation(ControlLimitsDataItem.TypeId)); if (!ControlLimitsDataSet.IsNullOrEmpty()) foreach (var x in ControlLimitsDataSet) l.Add(x.ToObservation(ControlLimitsDataItem.TypeId)); if (!ControlLimitsTable.IsNullOrEmpty()) foreach (var x in ControlLimitsTable) l.Add(x.ToObservation(ControlLimitsDataItem.TypeId)); @@ -277,10 +265,6 @@ public List Observations if (!LibraryDataSet.IsNullOrEmpty()) foreach (var x in LibraryDataSet) l.Add(x.ToObservation(LibraryDataItem.TypeId)); if (!LibraryTable.IsNullOrEmpty()) foreach (var x in LibraryTable) l.Add(x.ToObservation(LibraryDataItem.TypeId)); - if (!Line.IsNullOrEmpty()) foreach (var x in Line) l.Add(x.ToObservation(LineDataItem.TypeId)); - if (!LineDataSet.IsNullOrEmpty()) foreach (var x in LineDataSet) l.Add(x.ToObservation(LineDataItem.TypeId)); - if (!LineTable.IsNullOrEmpty()) foreach (var x in LineTable) l.Add(x.ToObservation(LineDataItem.TypeId)); - if (!LineLabel.IsNullOrEmpty()) foreach (var x in LineLabel) l.Add(x.ToObservation(LineLabelDataItem.TypeId)); if (!LineLabelDataSet.IsNullOrEmpty()) foreach (var x in LineLabelDataSet) l.Add(x.ToObservation(LineLabelDataItem.TypeId)); if (!LineLabelTable.IsNullOrEmpty()) foreach (var x in LineLabelTable) l.Add(x.ToObservation(LineLabelDataItem.TypeId)); @@ -393,10 +377,6 @@ public List Observations if (!PartKindIdDataSet.IsNullOrEmpty()) foreach (var x in PartKindIdDataSet) l.Add(x.ToObservation(PartKindIdDataItem.TypeId)); if (!PartKindIdTable.IsNullOrEmpty()) foreach (var x in PartKindIdTable) l.Add(x.ToObservation(PartKindIdDataItem.TypeId)); - if (!PartNumber.IsNullOrEmpty()) foreach (var x in PartNumber) l.Add(x.ToObservation(PartNumberDataItem.TypeId)); - if (!PartNumberDataSet.IsNullOrEmpty()) foreach (var x in PartNumberDataSet) l.Add(x.ToObservation(PartNumberDataItem.TypeId)); - if (!PartNumberTable.IsNullOrEmpty()) foreach (var x in PartNumberTable) l.Add(x.ToObservation(PartNumberDataItem.TypeId)); - if (!PartProcessingState.IsNullOrEmpty()) foreach (var x in PartProcessingState) l.Add(x.ToObservation(PartProcessingStateDataItem.TypeId)); if (!PartProcessingStateDataSet.IsNullOrEmpty()) foreach (var x in PartProcessingStateDataSet) l.Add(x.ToObservation(PartProcessingStateDataItem.TypeId)); if (!PartProcessingStateTable.IsNullOrEmpty()) foreach (var x in PartProcessingStateTable) l.Add(x.ToObservation(PartProcessingStateDataItem.TypeId)); @@ -421,10 +401,6 @@ public List Observations if (!PowerStateDataSet.IsNullOrEmpty()) foreach (var x in PowerStateDataSet) l.Add(x.ToObservation(PowerStateDataItem.TypeId)); if (!PowerStateTable.IsNullOrEmpty()) foreach (var x in PowerStateTable) l.Add(x.ToObservation(PowerStateDataItem.TypeId)); - if (!PowerStatus.IsNullOrEmpty()) foreach (var x in PowerStatus) l.Add(x.ToObservation(PowerStatusDataItem.TypeId)); - if (!PowerStatusDataSet.IsNullOrEmpty()) foreach (var x in PowerStatusDataSet) l.Add(x.ToObservation(PowerStatusDataItem.TypeId)); - if (!PowerStatusTable.IsNullOrEmpty()) foreach (var x in PowerStatusTable) l.Add(x.ToObservation(PowerStatusDataItem.TypeId)); - if (!ProcessAggregateId.IsNullOrEmpty()) foreach (var x in ProcessAggregateId) l.Add(x.ToObservation(ProcessAggregateIdDataItem.TypeId)); if (!ProcessAggregateIdDataSet.IsNullOrEmpty()) foreach (var x in ProcessAggregateIdDataSet) l.Add(x.ToObservation(ProcessAggregateIdDataItem.TypeId)); if (!ProcessAggregateIdTable.IsNullOrEmpty()) foreach (var x in ProcessAggregateIdTable) l.Add(x.ToObservation(ProcessAggregateIdDataItem.TypeId)); @@ -501,10 +477,6 @@ public List Observations if (!SerialNumberDataSet.IsNullOrEmpty()) foreach (var x in SerialNumberDataSet) l.Add(x.ToObservation(SerialNumberDataItem.TypeId)); if (!SerialNumberTable.IsNullOrEmpty()) foreach (var x in SerialNumberTable) l.Add(x.ToObservation(SerialNumberDataItem.TypeId)); - if (!SpecificationLimit.IsNullOrEmpty()) foreach (var x in SpecificationLimit) l.Add(x.ToObservation(SpecificationLimitDataItem.TypeId)); - if (!SpecificationLimitDataSet.IsNullOrEmpty()) foreach (var x in SpecificationLimitDataSet) l.Add(x.ToObservation(SpecificationLimitDataItem.TypeId)); - if (!SpecificationLimitTable.IsNullOrEmpty()) foreach (var x in SpecificationLimitTable) l.Add(x.ToObservation(SpecificationLimitDataItem.TypeId)); - if (!SpecificationLimits.IsNullOrEmpty()) foreach (var x in SpecificationLimits) l.Add(x.ToObservation(SpecificationLimitsDataItem.TypeId)); if (!SpecificationLimitsDataSet.IsNullOrEmpty()) foreach (var x in SpecificationLimitsDataSet) l.Add(x.ToObservation(SpecificationLimitsDataItem.TypeId)); if (!SpecificationLimitsTable.IsNullOrEmpty()) foreach (var x in SpecificationLimitsTable) l.Add(x.ToObservation(SpecificationLimitsDataItem.TypeId)); @@ -545,10 +517,6 @@ public List Observations if (!ToolGroupDataSet.IsNullOrEmpty()) foreach (var x in ToolGroupDataSet) l.Add(x.ToObservation(ToolGroupDataItem.TypeId)); if (!ToolGroupTable.IsNullOrEmpty()) foreach (var x in ToolGroupTable) l.Add(x.ToObservation(ToolGroupDataItem.TypeId)); - if (!ToolId.IsNullOrEmpty()) foreach (var x in ToolId) l.Add(x.ToObservation(ToolIdDataItem.TypeId)); - if (!ToolIdDataSet.IsNullOrEmpty()) foreach (var x in ToolIdDataSet) l.Add(x.ToObservation(ToolIdDataItem.TypeId)); - if (!ToolIdTable.IsNullOrEmpty()) foreach (var x in ToolIdTable) l.Add(x.ToObservation(ToolIdDataItem.TypeId)); - if (!ToolNumber.IsNullOrEmpty()) foreach (var x in ToolNumber) l.Add(x.ToObservation(ToolNumberDataItem.TypeId)); if (!ToolNumberDataSet.IsNullOrEmpty()) foreach (var x in ToolNumberDataSet) l.Add(x.ToObservation(ToolNumberDataItem.TypeId)); if (!ToolNumberTable.IsNullOrEmpty()) foreach (var x in ToolNumberTable) l.Add(x.ToObservation(ToolNumberDataItem.TypeId)); @@ -771,28 +739,6 @@ public List Observations public IEnumerable AlarmTable { get; set; } - /// - /// The AlarmLimit events reported with the scalar VALUE representation. - /// Set of limits used to trigger warning or alarm indicators.**DEPRECATED** in *Version 2.5*. Replaced by `ALARM_LIMITS`. - /// - [JsonPropertyName("AlarmLimit")] - public IEnumerable AlarmLimit { get; set; } - - /// - /// The AlarmLimit events reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("AlarmLimitDataSet")] - public IEnumerable AlarmLimitDataSet { get; set; } - - /// - /// The AlarmLimit events reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("AlarmLimitTable")] - public IEnumerable AlarmLimitTable { get; set; } - - /// /// The AlarmLimits events reported with the scalar VALUE representation. /// Set of limits used to trigger warning or alarm indicators. @@ -1255,28 +1201,6 @@ public List Observations public IEnumerable ClockTimeTable { get; set; } - /// - /// The Code events reported with the scalar VALUE representation. - /// Programmatic code being executed.**DEPRECATED** in *Version 1.1*. - /// - [JsonPropertyName("Code")] - public IEnumerable Code { get; set; } - - /// - /// The Code events reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("CodeDataSet")] - public IEnumerable CodeDataSet { get; set; } - - /// - /// The Code events reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("CodeTable")] - public IEnumerable CodeTable { get; set; } - - /// /// The ComponentData events reported with the scalar VALUE representation. /// Event that represents a Component where the EntryDefinition identifies the Component and the CellDefinitions define the Component's observed DataItems. @@ -1343,28 +1267,6 @@ public List Observations public IEnumerable ConnectionStatusTable { get; set; } - /// - /// The ControlLimit events reported with the scalar VALUE representation. - /// Set of limits used to indicate whether a process variable is stable and in control.**DEPRECATED** in *Version 2.5*. Replaced by `CONTROL_LIMITS`. - /// - [JsonPropertyName("ControlLimit")] - public IEnumerable ControlLimit { get; set; } - - /// - /// The ControlLimit events reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("ControlLimitDataSet")] - public IEnumerable ControlLimitDataSet { get; set; } - - /// - /// The ControlLimit events reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("ControlLimitTable")] - public IEnumerable ControlLimitTable { get; set; } - - /// /// The ControlLimits events reported with the scalar VALUE representation. /// Set of limits used to indicate whether a process variable is stable and in control. @@ -1981,28 +1883,6 @@ public List Observations public IEnumerable LibraryTable { get; set; } - /// - /// The Line events reported with the scalar VALUE representation. - /// Current line of code being executed.**DEPRECATED** in *Version 1.4.0*. - /// - [JsonPropertyName("Line")] - public IEnumerable Line { get; set; } - - /// - /// The Line events reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("LineDataSet")] - public IEnumerable LineDataSet { get; set; } - - /// - /// The Line events reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("LineTable")] - public IEnumerable LineTable { get; set; } - - /// /// The LineLabel events reported with the scalar VALUE representation. /// Identifier for a Block of code in a Program. @@ -2619,28 +2499,6 @@ public List Observations public IEnumerable PartKindIdTable { get; set; } - /// - /// The PartNumber events reported with the scalar VALUE representation. - /// Identifier of a part or product moving through the manufacturing process.**DEPRECATED** in *Version 1.7*. `PART_NUMBER` is now a `subType` of `PART_KIND_ID`. - /// - [JsonPropertyName("PartNumber")] - public IEnumerable PartNumber { get; set; } - - /// - /// The PartNumber events reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("PartNumberDataSet")] - public IEnumerable PartNumberDataSet { get; set; } - - /// - /// The PartNumber events reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("PartNumberTable")] - public IEnumerable PartNumberTable { get; set; } - - /// /// The PartProcessingState events reported with the scalar VALUE representation. /// Particular condition of the part occurrence at a specific time. @@ -2773,28 +2631,6 @@ public List Observations public IEnumerable PowerStateTable { get; set; } - /// - /// The PowerStatus events reported with the scalar VALUE representation. - /// Status of the Component.**DEPRECATED** in *Version 1.1.0*. - /// - [JsonPropertyName("PowerStatus")] - public IEnumerable PowerStatus { get; set; } - - /// - /// The PowerStatus events reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("PowerStatusDataSet")] - public IEnumerable PowerStatusDataSet { get; set; } - - /// - /// The PowerStatus events reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("PowerStatusTable")] - public IEnumerable PowerStatusTable { get; set; } - - /// /// The ProcessAggregateId events reported with the scalar VALUE representation. /// Identifier given to link the individual occurrence to a group of related occurrences, such as a process step in a process plan. @@ -3213,28 +3049,6 @@ public List Observations public IEnumerable SerialNumberTable { get; set; } - /// - /// The SpecificationLimit events reported with the scalar VALUE representation. - /// Set of limits defining a range of values designating acceptable performance for a variable.**DEPRECATED** in *Version 2.5*. Replaced by `SPECIFICATION_LIMITS`. - /// - [JsonPropertyName("SpecificationLimit")] - public IEnumerable SpecificationLimit { get; set; } - - /// - /// The SpecificationLimit events reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("SpecificationLimitDataSet")] - public IEnumerable SpecificationLimitDataSet { get; set; } - - /// - /// The SpecificationLimit events reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("SpecificationLimitTable")] - public IEnumerable SpecificationLimitTable { get; set; } - - /// /// The SpecificationLimits events reported with the scalar VALUE representation. /// Set of limits defining a range of values designating acceptable performance for a variable. @@ -3455,28 +3269,6 @@ public List Observations public IEnumerable ToolGroupTable { get; set; } - /// - /// The ToolId events reported with the scalar VALUE representation. - /// Identifier of the tool currently in use for a given `Path`.**DEPRECATED** in *Version 1.2.0*. See `TOOL_NUMBER`. - /// - [JsonPropertyName("ToolId")] - public IEnumerable ToolId { get; set; } - - /// - /// The ToolId events reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("ToolIdDataSet")] - public IEnumerable ToolIdDataSet { get; set; } - - /// - /// The ToolId events reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("ToolIdTable")] - public IEnumerable ToolIdTable { get; set; } - - /// /// The ToolNumber events reported with the scalar VALUE representation. /// Identifier assigned by the Controller component to a cutting tool when in use by a piece of equipment. @@ -4106,43 +3898,6 @@ public JsonEvents(IEnumerable observations) } - // Add AlarmLimit - typeObservations = observations.Where(o => o.Type == AlarmLimitDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventValue(observation)); - } - AlarmLimit = jsonObservations; - } - - // Add AlarmLimitDataSet - typeObservations = observations.Where(o => o.Type == AlarmLimitDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventDataSet(observation)); - } - AlarmLimitDataSet = jsonObservations; - } - - // Add AlarmLimitTable - typeObservations = observations.Where(o => o.Type == AlarmLimitDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventTable(observation)); - } - AlarmLimitTable = jsonObservations; - } - - // Add AlarmLimits typeObservations = observations.Where(o => o.Type == AlarmLimitsDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) @@ -4920,43 +4675,6 @@ public JsonEvents(IEnumerable observations) } - // Add Code - typeObservations = observations.Where(o => o.Type == CodeDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventValue(observation)); - } - Code = jsonObservations; - } - - // Add CodeDataSet - typeObservations = observations.Where(o => o.Type == CodeDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventDataSet(observation)); - } - CodeDataSet = jsonObservations; - } - - // Add CodeTable - typeObservations = observations.Where(o => o.Type == CodeDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventTable(observation)); - } - CodeTable = jsonObservations; - } - - // Add ComponentData typeObservations = observations.Where(o => o.Type == ComponentDataDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) @@ -5068,43 +4786,6 @@ public JsonEvents(IEnumerable observations) } - // Add ControlLimit - typeObservations = observations.Where(o => o.Type == ControlLimitDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventValue(observation)); - } - ControlLimit = jsonObservations; - } - - // Add ControlLimitDataSet - typeObservations = observations.Where(o => o.Type == ControlLimitDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventDataSet(observation)); - } - ControlLimitDataSet = jsonObservations; - } - - // Add ControlLimitTable - typeObservations = observations.Where(o => o.Type == ControlLimitDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventTable(observation)); - } - ControlLimitTable = jsonObservations; - } - - // Add ControlLimits typeObservations = observations.Where(o => o.Type == ControlLimitsDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) @@ -6141,43 +5822,6 @@ public JsonEvents(IEnumerable observations) } - // Add Line - typeObservations = observations.Where(o => o.Type == LineDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventValue(observation)); - } - Line = jsonObservations; - } - - // Add LineDataSet - typeObservations = observations.Where(o => o.Type == LineDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventDataSet(observation)); - } - LineDataSet = jsonObservations; - } - - // Add LineTable - typeObservations = observations.Where(o => o.Type == LineDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventTable(observation)); - } - LineTable = jsonObservations; - } - - // Add LineLabel typeObservations = observations.Where(o => o.Type == LineLabelDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) @@ -7214,43 +6858,6 @@ public JsonEvents(IEnumerable observations) } - // Add PartNumber - typeObservations = observations.Where(o => o.Type == PartNumberDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventValue(observation)); - } - PartNumber = jsonObservations; - } - - // Add PartNumberDataSet - typeObservations = observations.Where(o => o.Type == PartNumberDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventDataSet(observation)); - } - PartNumberDataSet = jsonObservations; - } - - // Add PartNumberTable - typeObservations = observations.Where(o => o.Type == PartNumberDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventTable(observation)); - } - PartNumberTable = jsonObservations; - } - - // Add PartProcessingState typeObservations = observations.Where(o => o.Type == PartProcessingStateDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) @@ -7473,43 +7080,6 @@ public JsonEvents(IEnumerable observations) } - // Add PowerStatus - typeObservations = observations.Where(o => o.Type == PowerStatusDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventValue(observation)); - } - PowerStatus = jsonObservations; - } - - // Add PowerStatusDataSet - typeObservations = observations.Where(o => o.Type == PowerStatusDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventDataSet(observation)); - } - PowerStatusDataSet = jsonObservations; - } - - // Add PowerStatusTable - typeObservations = observations.Where(o => o.Type == PowerStatusDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventTable(observation)); - } - PowerStatusTable = jsonObservations; - } - - // Add ProcessAggregateId typeObservations = observations.Where(o => o.Type == ProcessAggregateIdDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) @@ -8213,43 +7783,6 @@ public JsonEvents(IEnumerable observations) } - // Add SpecificationLimit - typeObservations = observations.Where(o => o.Type == SpecificationLimitDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventValue(observation)); - } - SpecificationLimit = jsonObservations; - } - - // Add SpecificationLimitDataSet - typeObservations = observations.Where(o => o.Type == SpecificationLimitDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventDataSet(observation)); - } - SpecificationLimitDataSet = jsonObservations; - } - - // Add SpecificationLimitTable - typeObservations = observations.Where(o => o.Type == SpecificationLimitDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventTable(observation)); - } - SpecificationLimitTable = jsonObservations; - } - - // Add SpecificationLimits typeObservations = observations.Where(o => o.Type == SpecificationLimitsDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) @@ -8620,43 +8153,6 @@ public JsonEvents(IEnumerable observations) } - // Add ToolId - typeObservations = observations.Where(o => o.Type == ToolIdDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventValue(observation)); - } - ToolId = jsonObservations; - } - - // Add ToolIdDataSet - typeObservations = observations.Where(o => o.Type == ToolIdDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventDataSet(observation)); - } - ToolIdDataSet = jsonObservations; - } - - // Add ToolIdTable - typeObservations = observations.Where(o => o.Type == ToolIdDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonEventTable(observation)); - } - ToolIdTable = jsonObservations; - } - - // Add ToolNumber typeObservations = observations.Where(o => o.Type == ToolNumberDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) diff --git a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonSamples.g.cs b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonSamples.g.cs index 147260756..d3f0f4033 100644 --- a/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonSamples.g.cs +++ b/libraries/MTConnect.NET-JSON-cppagent/Streams/JsonSamples.g.cs @@ -39,11 +39,6 @@ public List Observations if (!AccumulatedTimeTable.IsNullOrEmpty()) foreach (var x in AccumulatedTimeTable) l.Add(x.ToObservation(AccumulatedTimeDataItem.TypeId)); if (!AccumulatedTimeTimeSeries.IsNullOrEmpty()) foreach (var x in AccumulatedTimeTimeSeries) l.Add(x.ToObservation(AccumulatedTimeDataItem.TypeId)); - if (!Amperage.IsNullOrEmpty()) foreach (var x in Amperage) l.Add(x.ToObservation(AmperageDataItem.TypeId)); - if (!AmperageDataSet.IsNullOrEmpty()) foreach (var x in AmperageDataSet) l.Add(x.ToObservation(AmperageDataItem.TypeId)); - if (!AmperageTable.IsNullOrEmpty()) foreach (var x in AmperageTable) l.Add(x.ToObservation(AmperageDataItem.TypeId)); - if (!AmperageTimeSeries.IsNullOrEmpty()) foreach (var x in AmperageTimeSeries) l.Add(x.ToObservation(AmperageDataItem.TypeId)); - if (!AmperageAC.IsNullOrEmpty()) foreach (var x in AmperageAC) l.Add(x.ToObservation(AmperageACDataItem.TypeId)); if (!AmperageACDataSet.IsNullOrEmpty()) foreach (var x in AmperageACDataSet) l.Add(x.ToObservation(AmperageACDataItem.TypeId)); if (!AmperageACTable.IsNullOrEmpty()) foreach (var x in AmperageACTable) l.Add(x.ToObservation(AmperageACDataItem.TypeId)); @@ -234,11 +229,6 @@ public List Observations if (!FrequencyTable.IsNullOrEmpty()) foreach (var x in FrequencyTable) l.Add(x.ToObservation(FrequencyDataItem.TypeId)); if (!FrequencyTimeSeries.IsNullOrEmpty()) foreach (var x in FrequencyTimeSeries) l.Add(x.ToObservation(FrequencyDataItem.TypeId)); - if (!GlobalPosition.IsNullOrEmpty()) foreach (var x in GlobalPosition) l.Add(x.ToObservation(GlobalPositionDataItem.TypeId)); - if (!GlobalPositionDataSet.IsNullOrEmpty()) foreach (var x in GlobalPositionDataSet) l.Add(x.ToObservation(GlobalPositionDataItem.TypeId)); - if (!GlobalPositionTable.IsNullOrEmpty()) foreach (var x in GlobalPositionTable) l.Add(x.ToObservation(GlobalPositionDataItem.TypeId)); - if (!GlobalPositionTimeSeries.IsNullOrEmpty()) foreach (var x in GlobalPositionTimeSeries) l.Add(x.ToObservation(GlobalPositionDataItem.TypeId)); - if (!GravitationalAcceleration.IsNullOrEmpty()) foreach (var x in GravitationalAcceleration) l.Add(x.ToObservation(GravitationalAccelerationDataItem.TypeId)); if (!GravitationalAccelerationDataSet.IsNullOrEmpty()) foreach (var x in GravitationalAccelerationDataSet) l.Add(x.ToObservation(GravitationalAccelerationDataItem.TypeId)); if (!GravitationalAccelerationTable.IsNullOrEmpty()) foreach (var x in GravitationalAccelerationTable) l.Add(x.ToObservation(GravitationalAccelerationDataItem.TypeId)); @@ -404,11 +394,6 @@ public List Observations if (!SoundLevelTable.IsNullOrEmpty()) foreach (var x in SoundLevelTable) l.Add(x.ToObservation(SoundLevelDataItem.TypeId)); if (!SoundLevelTimeSeries.IsNullOrEmpty()) foreach (var x in SoundLevelTimeSeries) l.Add(x.ToObservation(SoundLevelDataItem.TypeId)); - if (!SpindleSpeed.IsNullOrEmpty()) foreach (var x in SpindleSpeed) l.Add(x.ToObservation(SpindleSpeedDataItem.TypeId)); - if (!SpindleSpeedDataSet.IsNullOrEmpty()) foreach (var x in SpindleSpeedDataSet) l.Add(x.ToObservation(SpindleSpeedDataItem.TypeId)); - if (!SpindleSpeedTable.IsNullOrEmpty()) foreach (var x in SpindleSpeedTable) l.Add(x.ToObservation(SpindleSpeedDataItem.TypeId)); - if (!SpindleSpeedTimeSeries.IsNullOrEmpty()) foreach (var x in SpindleSpeedTimeSeries) l.Add(x.ToObservation(SpindleSpeedDataItem.TypeId)); - if (!Strain.IsNullOrEmpty()) foreach (var x in Strain) l.Add(x.ToObservation(StrainDataItem.TypeId)); if (!StrainDataSet.IsNullOrEmpty()) foreach (var x in StrainDataSet) l.Add(x.ToObservation(StrainDataItem.TypeId)); if (!StrainTable.IsNullOrEmpty()) foreach (var x in StrainTable) l.Add(x.ToObservation(StrainDataItem.TypeId)); @@ -454,11 +439,6 @@ public List Observations if (!VoltAmpereReactiveTable.IsNullOrEmpty()) foreach (var x in VoltAmpereReactiveTable) l.Add(x.ToObservation(VoltAmpereReactiveDataItem.TypeId)); if (!VoltAmpereReactiveTimeSeries.IsNullOrEmpty()) foreach (var x in VoltAmpereReactiveTimeSeries) l.Add(x.ToObservation(VoltAmpereReactiveDataItem.TypeId)); - if (!Voltage.IsNullOrEmpty()) foreach (var x in Voltage) l.Add(x.ToObservation(VoltageDataItem.TypeId)); - if (!VoltageDataSet.IsNullOrEmpty()) foreach (var x in VoltageDataSet) l.Add(x.ToObservation(VoltageDataItem.TypeId)); - if (!VoltageTable.IsNullOrEmpty()) foreach (var x in VoltageTable) l.Add(x.ToObservation(VoltageDataItem.TypeId)); - if (!VoltageTimeSeries.IsNullOrEmpty()) foreach (var x in VoltageTimeSeries) l.Add(x.ToObservation(VoltageDataItem.TypeId)); - if (!VoltageAC.IsNullOrEmpty()) foreach (var x in VoltageAC) l.Add(x.ToObservation(VoltageACDataItem.TypeId)); if (!VoltageACDataSet.IsNullOrEmpty()) foreach (var x in VoltageACDataSet) l.Add(x.ToObservation(VoltageACDataItem.TypeId)); if (!VoltageACTable.IsNullOrEmpty()) foreach (var x in VoltageACTable) l.Add(x.ToObservation(VoltageACDataItem.TypeId)); @@ -566,35 +546,6 @@ public List Observations public IEnumerable AccumulatedTimeTimeSeries { get; set; } - /// - /// The Amperage samples reported with the scalar VALUE representation. - /// Strength of electrical current.**DEPRECATED** in *Version 1.6*. Replaced by `AMPERAGE_AC` and `AMPERAGE_DC`. - /// - [JsonPropertyName("Amperage")] - public IEnumerable Amperage { get; set; } - - /// - /// The Amperage samples reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("AmperageDataSet")] - public IEnumerable AmperageDataSet { get; set; } - - /// - /// The Amperage samples reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("AmperageTable")] - public IEnumerable AmperageTable { get; set; } - - /// - /// The Amperage samples reported with the TIME_SERIES representation - /// (a sequence of values sampled at a fixed rate). - /// - [JsonPropertyName("AmperageTimeSeries")] - public IEnumerable AmperageTimeSeries { get; set; } - - /// /// The AmperageAC samples reported with the scalar VALUE representation. /// Electrical current that reverses direction at regular short intervals. @@ -1697,35 +1648,6 @@ public List Observations public IEnumerable FrequencyTimeSeries { get; set; } - /// - /// The GlobalPosition samples reported with the scalar VALUE representation. - /// Position in three-dimensional space.**DEPRECATED** in Version 1.1. - /// - [JsonPropertyName("GlobalPosition")] - public IEnumerable GlobalPosition { get; set; } - - /// - /// The GlobalPosition samples reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("GlobalPositionDataSet")] - public IEnumerable GlobalPositionDataSet { get; set; } - - /// - /// The GlobalPosition samples reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("GlobalPositionTable")] - public IEnumerable GlobalPositionTable { get; set; } - - /// - /// The GlobalPosition samples reported with the TIME_SERIES representation - /// (a sequence of values sampled at a fixed rate). - /// - [JsonPropertyName("GlobalPositionTimeSeries")] - public IEnumerable GlobalPositionTimeSeries { get; set; } - - /// /// The GravitationalAcceleration samples reported with the scalar VALUE representation. /// Acceleration relative to Earth's gravity of 9.80665 `METER/SECOND^2`. @@ -2683,35 +2605,6 @@ public List Observations public IEnumerable SoundLevelTimeSeries { get; set; } - /// - /// The SpindleSpeed samples reported with the scalar VALUE representation. - /// Rotational speed of the rotary axis.**DEPRECATED** in *Version 1.2*. Replaced by `ROTARY_VELOCITY`. - /// - [JsonPropertyName("SpindleSpeed")] - public IEnumerable SpindleSpeed { get; set; } - - /// - /// The SpindleSpeed samples reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("SpindleSpeedDataSet")] - public IEnumerable SpindleSpeedDataSet { get; set; } - - /// - /// The SpindleSpeed samples reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("SpindleSpeedTable")] - public IEnumerable SpindleSpeedTable { get; set; } - - /// - /// The SpindleSpeed samples reported with the TIME_SERIES representation - /// (a sequence of values sampled at a fixed rate). - /// - [JsonPropertyName("SpindleSpeedTimeSeries")] - public IEnumerable SpindleSpeedTimeSeries { get; set; } - - /// /// The Strain samples reported with the scalar VALUE representation. /// Amount of deformation per unit length of an object when a load is applied. @@ -2973,35 +2866,6 @@ public List Observations public IEnumerable VoltAmpereReactiveTimeSeries { get; set; } - /// - /// The Voltage samples reported with the scalar VALUE representation. - /// Electrical potential between two points.**DEPRECATED** in *Version 1.6*. Replaced by `VOLTAGE_AC` and `VOLTAGE_DC`. - /// - [JsonPropertyName("Voltage")] - public IEnumerable Voltage { get; set; } - - /// - /// The Voltage samples reported with the DATA_SET representation - /// (a set of key/value entries). - /// - [JsonPropertyName("VoltageDataSet")] - public IEnumerable VoltageDataSet { get; set; } - - /// - /// The Voltage samples reported with the TABLE representation - /// (a set of keyed rows of cells). - /// - [JsonPropertyName("VoltageTable")] - public IEnumerable VoltageTable { get; set; } - - /// - /// The Voltage samples reported with the TIME_SERIES representation - /// (a sequence of values sampled at a fixed rate). - /// - [JsonPropertyName("VoltageTimeSeries")] - public IEnumerable VoltageTimeSeries { get; set; } - - /// /// The VoltageAC samples reported with the scalar VALUE representation. /// Electrical potential between two points in an electrical circuit in which the current periodically reverses direction. @@ -3379,55 +3243,6 @@ public JsonSamples(IEnumerable observations) } - // Add Amperage - typeObservations = observations.Where(o => o.Type == AmperageDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleValue(observation)); - } - Amperage = jsonObservations; - } - - // Add AmperageDataSet - typeObservations = observations.Where(o => o.Type == AmperageDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleDataSet(observation)); - } - AmperageDataSet = jsonObservations; - } - - // Add AmperageTable - typeObservations = observations.Where(o => o.Type == AmperageDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleTable(observation)); - } - AmperageTable = jsonObservations; - } - - // Add AmperageTimeSeries - typeObservations = observations.Where(o => o.Type == AmperageDataItem.TypeId && o.Representation == DataItemRepresentation.TIME_SERIES); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleTimeSeries(observation)); - } - AmperageTimeSeries = jsonObservations; - } - - // Add AmperageAC typeObservations = observations.Where(o => o.Type == AmperageACDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) @@ -5290,55 +5105,6 @@ public JsonSamples(IEnumerable observations) } - // Add GlobalPosition - typeObservations = observations.Where(o => o.Type == GlobalPositionDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleValue(observation)); - } - GlobalPosition = jsonObservations; - } - - // Add GlobalPositionDataSet - typeObservations = observations.Where(o => o.Type == GlobalPositionDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleDataSet(observation)); - } - GlobalPositionDataSet = jsonObservations; - } - - // Add GlobalPositionTable - typeObservations = observations.Where(o => o.Type == GlobalPositionDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleTable(observation)); - } - GlobalPositionTable = jsonObservations; - } - - // Add GlobalPositionTimeSeries - typeObservations = observations.Where(o => o.Type == GlobalPositionDataItem.TypeId && o.Representation == DataItemRepresentation.TIME_SERIES); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleTimeSeries(observation)); - } - GlobalPositionTimeSeries = jsonObservations; - } - - // Add GravitationalAcceleration typeObservations = observations.Where(o => o.Type == GravitationalAccelerationDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) @@ -6956,55 +6722,6 @@ public JsonSamples(IEnumerable observations) } - // Add SpindleSpeed - typeObservations = observations.Where(o => o.Type == SpindleSpeedDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleValue(observation)); - } - SpindleSpeed = jsonObservations; - } - - // Add SpindleSpeedDataSet - typeObservations = observations.Where(o => o.Type == SpindleSpeedDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleDataSet(observation)); - } - SpindleSpeedDataSet = jsonObservations; - } - - // Add SpindleSpeedTable - typeObservations = observations.Where(o => o.Type == SpindleSpeedDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleTable(observation)); - } - SpindleSpeedTable = jsonObservations; - } - - // Add SpindleSpeedTimeSeries - typeObservations = observations.Where(o => o.Type == SpindleSpeedDataItem.TypeId && o.Representation == DataItemRepresentation.TIME_SERIES); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleTimeSeries(observation)); - } - SpindleSpeedTimeSeries = jsonObservations; - } - - // Add Strain typeObservations = observations.Where(o => o.Type == StrainDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) @@ -7446,55 +7163,6 @@ public JsonSamples(IEnumerable observations) } - // Add Voltage - typeObservations = observations.Where(o => o.Type == VoltageDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleValue(observation)); - } - Voltage = jsonObservations; - } - - // Add VoltageDataSet - typeObservations = observations.Where(o => o.Type == VoltageDataItem.TypeId && o.Representation == DataItemRepresentation.DATA_SET); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleDataSet(observation)); - } - VoltageDataSet = jsonObservations; - } - - // Add VoltageTable - typeObservations = observations.Where(o => o.Type == VoltageDataItem.TypeId && o.Representation == DataItemRepresentation.TABLE); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleTable(observation)); - } - VoltageTable = jsonObservations; - } - - // Add VoltageTimeSeries - typeObservations = observations.Where(o => o.Type == VoltageDataItem.TypeId && o.Representation == DataItemRepresentation.TIME_SERIES); - if (!typeObservations.IsNullOrEmpty()) - { - var jsonObservations = new List(); - foreach (var observation in typeObservations) - { - jsonObservations.Add(new JsonSampleTimeSeries(observation)); - } - VoltageTimeSeries = jsonObservations; - } - - // Add VoltageAC typeObservations = observations.Where(o => o.Type == VoltageACDataItem.TypeId && o.Representation == DataItemRepresentation.VALUE); if (!typeObservations.IsNullOrEmpty()) diff --git a/stryker-config.json b/stryker-config.json new file mode 100644 index 000000000..9350ece7c --- /dev/null +++ b/stryker-config.json @@ -0,0 +1,57 @@ +// Baseline mutation score is 7.75% on 2026-08-20 (measured with +// MTConnect.NET-Common as the pilot assembly + the full +// MTConnect.NET-Common-Tests suite, at PR #233 head 43497c5d, Stryker.NET +// v4.16.0 with the Regex mutator ignored). +// +// Thresholds. `break: 5` and `low: 5` sit below the 7.75% baseline, so a +// baseline-conforming run passes CI (Stryker exits non-zero only when the +// score drops below `break`). `high: 8` sits deliberately ABOVE the +// baseline as an aspirational marker — a baseline-conforming run reports +// yellow (`low <= score < high`) rather than green, keeping visible +// pressure on the follow-up campaign until the floor rises above `high`. +// See TrakHound/MTConnect.NET#242 for the phase-by-phase plan +// (categorize survivors -> kill by subsystem -> raise thresholds in step +// to 20 -> 40 -> 60 -> 80%+ -> expand Stryker to sibling assemblies). +// +// Stryker.NET tool version is pinned in `.config/dotnet-tools.json` +// alongside the thresholds so the 7.75% baseline stays reproducible; a +// mutator-set change in a later Stryker release could shift the score +// even against unchanged production code. +// +// JSONC (JSON with comments) is the Stryker.NET native config format; +// leave these comments in place through subsequent edits. +{ + "stryker-config": { + "project": "MTConnect.NET-Common.csproj", + "solution": "MTConnect.NET.sln", + "test-projects": [ + "tests/MTConnect.NET-Common-Tests/MTConnect.NET-Common-Tests.csproj" + ], + "target-framework": "net8.0", + "reporters": [ + "progress", + "cleartext", + "html", + "json" + ], + "thresholds": { + "high": 8, + "low": 5, + "break": 5 + }, + "concurrency": 4, + "mutation-level": "Complete", + "since": { + "enabled": false + }, + "mutate": [ + "!**/*.g.cs", + "!libraries/MTConnect.NET-Common/Assets/**/*.g.cs", + "!libraries/MTConnect.NET-Common/Devices/**/*.g.cs", + "!libraries/MTConnect.NET-Common/Observations/**/*.g.cs" + ], + "ignore-mutations": [ + "Regex" + ] + } +} diff --git a/tests/MTConnect.NET-Common-Tests/Agents/AddObservationEmptyResultCoerceTests.cs b/tests/MTConnect.NET-Common-Tests/Agents/AddObservationEmptyResultCoerceTests.cs index d1195af65..42187c4f8 100644 --- a/tests/MTConnect.NET-Common-Tests/Agents/AddObservationEmptyResultCoerceTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Agents/AddObservationEmptyResultCoerceTests.cs @@ -28,7 +28,7 @@ namespace MTConnect.Tests.Common.Agents /// other Type with a controlled vocabulary) are coerced by default; the /// escape hatch /// preserves the empty Result when set to true. - /// Free-form String Events (PROGRAM, MESSAGE, TOOL_ID, ASSET_CHANGED, and + /// Free-form String Events (PROGRAM, MESSAGE, TOOL_NUMBER, ASSET_CHANGED, and /// every other non-vocabulary Type) preserve the empty Result verbatim: the /// standard's default value type for Observation::result is string, /// and the reference C++ agent accepts empty strings for these Events @@ -78,8 +78,8 @@ public class AddObservationEmptyResultCoerceTests [TestCaseSource(nameof(_nonStrictLevels))] public void Sample_EmptyResult_Coerced_To_Unavailable_Under_NonStrict_Levels(InputValidationLevel level) { - const string dataItemKey = SpindleSpeedDataItem.NameId; - using var agent = NewAgent(level, dataItem: new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL)); + const string dataItemKey = RotaryVelocityDataItem.NameId; + using var agent = NewAgent(level, dataItem: new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL)); var added = agent.AddObservation(DeviceKey, dataItemKey, (object)string.Empty, DateTime.UtcNow); @@ -93,8 +93,8 @@ public void Sample_EmptyResult_Coerced_To_Unavailable_Under_NonStrict_Levels(Inp [TestCaseSource(nameof(_nullEmptyWhitespaceValues))] public void Sample_NullEmptyOrWhitespaceResult_Coerced_To_Unavailable(object? badValue) { - const string dataItemKey = SpindleSpeedDataItem.NameId; - using var agent = NewAgent(InputValidationLevel.Warning, dataItem: new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL)); + const string dataItemKey = RotaryVelocityDataItem.NameId; + using var agent = NewAgent(InputValidationLevel.Warning, dataItem: new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL)); var added = agent.AddObservation(DeviceKey, dataItemKey, (object?)badValue!, DateTime.UtcNow); @@ -106,8 +106,8 @@ public void Sample_NullEmptyOrWhitespaceResult_Coerced_To_Unavailable(object? ba [Test] public void Sample_EmptyResult_Under_Strict_Coerced_And_Lands() { - const string dataItemKey = SpindleSpeedDataItem.NameId; - using var agent = NewAgent(InputValidationLevel.Strict, dataItem: new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL)); + const string dataItemKey = RotaryVelocityDataItem.NameId; + using var agent = NewAgent(InputValidationLevel.Strict, dataItem: new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL)); var added = agent.AddObservation(DeviceKey, dataItemKey, (object)string.Empty, DateTime.UtcNow); @@ -215,19 +215,19 @@ public void StringEvent_Message_EmptyResult_Preserved() "MESSAGE is a free-form String Event Type; empty Results MUST be preserved"); } - /// Empty Result on a TOOL_ID Event DataItem is preserved verbatim. + /// Empty Result on a TOOL_NUMBER Event DataItem is preserved verbatim. [Test] - public void StringEvent_ToolId_EmptyResult_Preserved() + public void StringEvent_ToolNumber_EmptyResult_Preserved() { - const string dataItemKey = ToolIdDataItem.NameId; - using var agent = NewAgent(InputValidationLevel.Warning, dataItem: new ToolIdDataItem(DeviceId)); + const string dataItemKey = ToolNumberDataItem.NameId; + using var agent = NewAgent(InputValidationLevel.Warning, dataItem: new ToolNumberDataItem(DeviceId)); var added = agent.AddObservation(DeviceKey, dataItemKey, (object)string.Empty, DateTime.UtcNow); Assert.That(added, Is.True); var currentResult = (CurrentResult(agent, dataItemKey) as string) ?? string.Empty; Assert.That(currentResult, Is.EqualTo(string.Empty), - "TOOL_ID is a free-form String Event Type; empty Results MUST be preserved"); + "TOOL_NUMBER is a free-form String Event Type; empty Results MUST be preserved"); } /// A concrete String Result is passed through verbatim on a free-form Event DataItem. @@ -364,7 +364,7 @@ public void DataItemValueClass_All_Enum_Arms_Are_Reachable_From_GetValueClass() { var observedArms = new System.Collections.Generic.HashSet { - DataItem.GetValueClass(new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL)), + DataItem.GetValueClass(new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL)), DataItem.GetValueClass(new AvailabilityDataItem(DeviceId)), DataItem.GetValueClass(new ProgramDataItem(DeviceId, ProgramDataItem.SubTypes.ACTIVE)), }; @@ -385,7 +385,7 @@ public void DataItemValueClass_All_Enum_Arms_Are_Reachable_From_GetValueClass() [Test] public void GetValueClass_Classifies_Representative_DataItems() { - Assert.That(DataItem.GetValueClass(new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL)), Is.EqualTo(DataItemValueClass.Numeric), + Assert.That(DataItem.GetValueClass(new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL)), Is.EqualTo(DataItemValueClass.Numeric), "SAMPLE observations are Numeric per Part 2 - Sample MUST be float"); Assert.That(DataItem.GetValueClass(new AvailabilityDataItem(DeviceId)), Is.EqualTo(DataItemValueClass.Enumeration), "AVAILABILITY has a controlled vocabulary (Availability enum)"); @@ -395,7 +395,7 @@ public void GetValueClass_Classifies_Representative_DataItems() "PROGRAM carries free-form text"); Assert.That(DataItem.GetValueClass(new MessageDataItem(DeviceId)), Is.EqualTo(DataItemValueClass.String), "MESSAGE carries free-form text"); - Assert.That(DataItem.GetValueClass(new ToolIdDataItem(DeviceId)), Is.EqualTo(DataItemValueClass.String), + Assert.That(DataItem.GetValueClass(new ToolNumberDataItem(DeviceId)), Is.EqualTo(DataItemValueClass.String), "TOOL_ID carries free-form text"); Assert.That(DataItem.GetValueClass(new AssetChangedDataItem(DeviceId)), Is.EqualTo(DataItemValueClass.String), "ASSET_CHANGED carries the asset id as free-form text"); @@ -419,8 +419,8 @@ public void GetValueClass_Classifies_Representative_DataItems() [Test] public void Sample_TimeSeries_Payload_Preserved_Not_Coerced() { - const string dataItemKey = SpindleSpeedDataItem.NameId; - var dataItem = new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL) + const string dataItemKey = RotaryVelocityDataItem.NameId; + var dataItem = new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL) { Representation = DataItemRepresentation.TIME_SERIES, }; @@ -451,8 +451,8 @@ public void Sample_TimeSeries_Payload_Preserved_Not_Coerced() [Test] public void Sample_DataSet_Payload_Preserved_Not_Coerced() { - const string dataItemKey = SpindleSpeedDataItem.NameId; - var dataItem = new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL) + const string dataItemKey = RotaryVelocityDataItem.NameId; + var dataItem = new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL) { Representation = DataItemRepresentation.DATA_SET, }; @@ -484,8 +484,8 @@ public void Sample_DataSet_Payload_Preserved_Not_Coerced() [Test] public void Sample_Table_Payload_Preserved_Not_Coerced() { - const string dataItemKey = SpindleSpeedDataItem.NameId; - var dataItem = new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL) + const string dataItemKey = RotaryVelocityDataItem.NameId; + var dataItem = new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL) { Representation = DataItemRepresentation.TABLE, }; @@ -520,21 +520,21 @@ public void Sample_Table_Payload_Preserved_Not_Coerced() [Test] public void GetValueClass_Sample_NonValueRepresentation_Is_String() { - var timeSeries = new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL) + var timeSeries = new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL) { Representation = DataItemRepresentation.TIME_SERIES, }; Assert.That(DataItem.GetValueClass(timeSeries), Is.EqualTo(DataItemValueClass.String), "SAMPLE + TIME_SERIES carries a Samples payload rather than a single Result - the classifier must not report Numeric"); - var dataSet = new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL) + var dataSet = new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL) { Representation = DataItemRepresentation.DATA_SET, }; Assert.That(DataItem.GetValueClass(dataSet), Is.EqualTo(DataItemValueClass.String), "SAMPLE + DATA_SET carries an Entries payload rather than a single Result - the classifier must not report Numeric"); - var table = new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL) + var table = new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL) { Representation = DataItemRepresentation.TABLE, }; @@ -727,8 +727,8 @@ public void EnumEvent_Table_Payload_Preserved_Not_Coerced() [Test] public void Sample_TimeSeries_Explicit_EmptyResult_Preserved() { - const string dataItemKey = SpindleSpeedDataItem.NameId; - var dataItem = new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL) + const string dataItemKey = RotaryVelocityDataItem.NameId; + var dataItem = new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL) { Representation = DataItemRepresentation.TIME_SERIES, }; @@ -763,8 +763,8 @@ public void Sample_TimeSeries_Explicit_EmptyResult_Preserved() [Test] public void Sample_DataSet_Explicit_WhitespaceResult_Preserved() { - const string dataItemKey = SpindleSpeedDataItem.NameId; - var dataItem = new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL) + const string dataItemKey = RotaryVelocityDataItem.NameId; + var dataItem = new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL) { Representation = DataItemRepresentation.DATA_SET, }; @@ -798,8 +798,8 @@ public void Sample_DataSet_Explicit_WhitespaceResult_Preserved() [Test] public void Sample_Table_Explicit_EmptyResult_Preserved() { - const string dataItemKey = SpindleSpeedDataItem.NameId; - var dataItem = new SpindleSpeedDataItem(DeviceId, SpindleSpeedDataItem.SubTypes.ACTUAL) + const string dataItemKey = RotaryVelocityDataItem.NameId; + var dataItem = new RotaryVelocityDataItem(DeviceId, RotaryVelocityDataItem.SubTypes.ACTUAL) { Representation = DataItemRepresentation.TABLE, }; diff --git a/tests/MTConnect.NET-Common-Tests/Devices/Components/ComponentTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/Components/ComponentTests.cs new file mode 100644 index 000000000..4246ee871 --- /dev/null +++ b/tests/MTConnect.NET-Common-Tests/Devices/Components/ComponentTests.cs @@ -0,0 +1,104 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using MTConnect.Devices.Components; +using MTConnect.Tests.Common.TestHelpers; +using NUnit.Framework; + +namespace MTConnect.NET_Common_Tests.Devices.Components +{ + // Version-gated shape assertions for the Component subclasses introduced + // across the v2.6 and v2.7 MTConnect Standard releases. + // + // - XMI: https://github.com/mtconnect/mtconnect_sysml_model tags + // v2.6 (SHA 08185447bf86…) — CuttingTorch, Electrode + // v2.7 (SHA 25796ac591bb…) — PinTool, ToolHolder + // UML classes under Device Information Model > Components. + // - XSD: https://schemas.mtconnect.org/schemas/MTConnectDevices_2.6.xsd + // MTConnectDevices_2.7.xsd + // (each TypeId appears in the ComponentType enumeration.) + // - Prose: MTConnect Standard Part_2.0_Devices_v2.6 section 3.4.18 + // "CuttingTorch" / section 3.4.21 "Electrode"; + // Part_2.0_Devices_v2.7 section 7 "Component types" (PinTool, + // ToolHolder). + // + // Every fixture below is matrix-parameterised over + // MTConnectVersionMatrix.All per plan Design Decision D1 + // (2026-08-19); Assume.That gates each assertion to versions where the + // spec introduced the type. Rows below the floor surface as + // Inconclusive in the test explorer, which is the D1-ruled shape for + // "gated out" versus "ran and passed". + /// Pins the behavior expressed by the test name: component tests. + [TestFixture] + public class ComponentTests + { + // Source: XMI v2.6 UML `CuttingTorch` (Component Types); XSD v2.6 + // ``. + /// Pins the behavior expressed by the test name: cutting torch component constructs with correct type. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void CuttingTorchComponent_constructs_with_correct_type(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version26), + "CuttingTorch was introduced in MTConnect v2.6."); + + var c = new CuttingTorchComponent(); + Assert.That(c.Type, Is.EqualTo("CuttingTorch")); + Assert.That(c.Name, Is.Null); + Assert.That(CuttingTorchComponent.TypeId, Is.EqualTo("CuttingTorch")); + Assert.That(CuttingTorchComponent.NameId, Is.EqualTo("cuttingTorch")); + } + + // Source: XMI v2.6 UML `Electrode` (Component Types); XSD v2.6 + // ``. + /// Pins the behavior expressed by the test name: electrode component constructs with correct type. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void ElectrodeComponent_constructs_with_correct_type(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version26), + "Electrode was introduced in MTConnect v2.6."); + + var c = new ElectrodeComponent(); + Assert.That(c.Type, Is.EqualTo("Electrode")); + Assert.That(c.Name, Is.Null); + Assert.That(ElectrodeComponent.TypeId, Is.EqualTo("Electrode")); + Assert.That(ElectrodeComponent.NameId, Is.EqualTo("electrode")); + } + + // Source: XMI v2.7 UML `PinTool` (Component Types); XSD v2.7 + // ComponentType enumeration value `PinTool`. + /// Pins the behavior expressed by the test name: pin tool component constructs with correct type. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void PinToolComponent_constructs_with_correct_type(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "PinTool was introduced in MTConnect v2.7."); + + var c = new PinToolComponent(); + Assert.That(c.Type, Is.EqualTo("PinTool")); + Assert.That(c.Name, Is.Null); + Assert.That(PinToolComponent.TypeId, Is.EqualTo("PinTool")); + Assert.That(PinToolComponent.NameId, Is.EqualTo("pinTool")); + } + + // Source: XMI v2.7 UML `ToolHolder` (Component Types); XSD v2.7 + // ComponentType enumeration value `ToolHolder`. + /// Pins the behavior expressed by the test name: tool holder component constructs with correct type. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void ToolHolderComponent_constructs_with_correct_type(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "ToolHolder was introduced in MTConnect v2.7."); + + var c = new ToolHolderComponent(); + Assert.That(c.Type, Is.EqualTo("ToolHolder")); + Assert.That(c.Name, Is.Null); + Assert.That(ToolHolderComponent.TypeId, Is.EqualTo("ToolHolder")); + Assert.That(ToolHolderComponent.NameId, Is.EqualTo("toolHolder")); + } + } +} diff --git a/tests/MTConnect.NET-Common-Tests/Devices/Configurations/ConfigurationTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/Configurations/ConfigurationTests.cs new file mode 100644 index 000000000..5f5ba17dc --- /dev/null +++ b/tests/MTConnect.NET-Common-Tests/Devices/Configurations/ConfigurationTests.cs @@ -0,0 +1,252 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using MTConnect.Devices.Configurations; +using MTConnect.Tests.Common.TestHelpers; +using NUnit.Framework; + +namespace MTConnect.NET_Common_Tests.Devices.Configurations +{ + // Version-gated shape assertions for the v2.7 Configuration sub-element + // family: new geometric primitives (Axis, Origin, Rotation, Scale, + // Translation) and their data-set representation siblings (*DataSet), + // plus the cross-package-grafted DataSet base that the universal + // cross-package parent resolver brought into the Devices.Configurations + // namespace. + // + // - XMI: https://github.com/mtconnect/mtconnect_sysml_model @ tag v2.7 + // UML classes under Device Information Model > Configurations: + // * Axis / AxisDataSet + // * Origin / OriginDataSet + // * Rotation / RotationDataSet + // * Scale / ScaleDataSet + // * Translation / TranslationDataSet + // plus the abstract bases (AbstractAxis, AbstractOrigin, etc.). + // - XSD: https://schemas.mtconnect.org/schemas/MTConnectDevices_2.7.xsd + // (the geometric-primitive complexTypes encode the same shape + // on the wire under ). + // - 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. + // + // Every fixture below is matrix-parameterised over + // MTConnectVersionMatrix.All per plan Design Decision D1 + // (2026-08-19). Assume.That gates every assertion to v2.7 (the version + // that introduced the Configuration family); rows below the floor + // surface as Inconclusive. + /// Pins the behavior expressed by the test name: configuration tests. + [TestFixture] + public class ConfigurationTests + { + // The DataSet base (grafted from Observation.Representations via the + // universal resolver) compiles, instantiates, and surfaces its + // const description. + /// Pins the behavior expressed by the test name: data set base constructs and implements i data set. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void DataSet_base_constructs_and_implements_IDataSet(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "DataSet was grafted into Devices.Configurations in MTConnect v2.7."); + + var ds = new DataSet(); + Assert.That(ds, Is.InstanceOf()); + Assert.That(DataSet.DescriptionText, Is.Not.Null.And.Not.Empty); + } + + // The five concrete sub-types follow the same shape: parameterless + // ctor, populates X/Y/Z (or A/B/C) fields, implements IDataSet + // (interface, not the concrete DataSet base — *DataSet types + // polymorphically extend their Abstract base, gaining IDataSet + // as a marker interface so XML/JSON serializers can narrow on it). + /// Pins the behavior expressed by the test name: axis data set has xyz fields and implements i data set. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AxisDataSet_has_xyz_fields_and_implements_IDataSet(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "AxisDataSet was introduced in MTConnect v2.7."); + + var a = new AxisDataSet { X = 1.0, Y = 2.0, Z = 3.0 }; + Assert.That(a, Is.InstanceOf()); + Assert.That(a, Is.InstanceOf()); + Assert.That(a.X, Is.EqualTo(1.0)); + Assert.That(a.Y, Is.EqualTo(2.0)); + Assert.That(a.Z, Is.EqualTo(3.0)); + } + + /// Pins the behavior expressed by the test name: origin data set has xyz fields and implements i data set. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void OriginDataSet_has_xyz_fields_and_implements_IDataSet(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "OriginDataSet was introduced in MTConnect v2.7."); + + var o = new OriginDataSet { X = "1", Y = "2", Z = "3" }; + Assert.That(o, Is.InstanceOf()); + Assert.That(o, Is.InstanceOf()); + } + + /// Pins the behavior expressed by the test name: rotation data set has abc fields and implements i data set. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void RotationDataSet_has_abc_fields_and_implements_IDataSet(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "RotationDataSet was introduced in MTConnect v2.7."); + + // Rotations are reported as A (about X), B (about Y), C (about Z). + var r = new RotationDataSet { A = "10", B = "20", C = "30" }; + Assert.That(r, Is.InstanceOf()); + Assert.That(r, Is.InstanceOf()); + } + + /// Pins the behavior expressed by the test name: scale data set implements i data set. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void ScaleDataSet_implements_IDataSet(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "ScaleDataSet was introduced in MTConnect v2.7."); + + var s = new ScaleDataSet(); + Assert.That(s, Is.InstanceOf()); + Assert.That(s, Is.InstanceOf()); + } + + /// Pins the behavior expressed by the test name: translation data set implements i data set. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void TranslationDataSet_implements_IDataSet(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "TranslationDataSet was introduced in MTConnect v2.7."); + + var t = new TranslationDataSet(); + Assert.That(t, Is.InstanceOf()); + Assert.That(t, Is.InstanceOf()); + } + + // Concrete (non-DataSet) representations of the same primitives, + // also landed in v2.7 alongside their DataSet siblings. + /// Pins the behavior expressed by the test name: axis inherits abstract axis and constructs. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void Axis_inherits_AbstractAxis_and_constructs(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "Axis was introduced in MTConnect v2.7."); + + var a = new Axis { Value = "X" }; + Assert.That(a, Is.InstanceOf()); + Assert.That(a, Is.InstanceOf()); + Assert.That(a.Value, Is.EqualTo("X")); + } + + /// Pins the behavior expressed by the test name: origin inherits abstract origin. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void Origin_inherits_AbstractOrigin(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "Origin was introduced in MTConnect v2.7."); + + var o = new Origin(); + Assert.That(o, Is.InstanceOf()); + Assert.That(o, Is.InstanceOf()); + } + + /// Pins the behavior expressed by the test name: rotation inherits abstract rotation. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void Rotation_inherits_AbstractRotation(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "Rotation was introduced in MTConnect v2.7."); + + Assert.That(new Rotation(), Is.InstanceOf()); + } + + /// Pins the behavior expressed by the test name: scale inherits abstract scale. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void Scale_inherits_AbstractScale(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "Scale was introduced in MTConnect v2.7."); + + Assert.That(new Scale(), Is.InstanceOf()); + } + + /// Pins the behavior expressed by the test name: translation inherits abstract translation. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void Translation_inherits_AbstractTranslation(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "Translation was introduced in MTConnect v2.7."); + + Assert.That(new Translation(), Is.InstanceOf()); + } + + // The Abstract* bases are abstract — verify so a future regen that + // accidentally drops the abstract modifier trips here. + /// Pins the behavior expressed by the test name: abstract axis is abstract. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AbstractAxis_is_abstract(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "AbstractAxis was introduced in MTConnect v2.7."); + + Assert.That(typeof(AbstractAxis).IsAbstract, Is.True); + } + + /// Pins the behavior expressed by the test name: abstract origin is abstract. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AbstractOrigin_is_abstract(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "AbstractOrigin was introduced in MTConnect v2.7."); + + Assert.That(typeof(AbstractOrigin).IsAbstract, Is.True); + } + + /// Pins the behavior expressed by the test name: abstract rotation is abstract. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AbstractRotation_is_abstract(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "AbstractRotation was introduced in MTConnect v2.7."); + + Assert.That(typeof(AbstractRotation).IsAbstract, Is.True); + } + + /// Pins the behavior expressed by the test name: abstract scale is abstract. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AbstractScale_is_abstract(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "AbstractScale was introduced in MTConnect v2.7."); + + Assert.That(typeof(AbstractScale).IsAbstract, Is.True); + } + + /// Pins the behavior expressed by the test name: abstract translation is abstract. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AbstractTranslation_is_abstract(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "AbstractTranslation was introduced in MTConnect v2.7."); + + Assert.That(typeof(AbstractTranslation).IsAbstract, Is.True); + } + } +} diff --git a/tests/MTConnect.NET-Common-Tests/Devices/DataItems/DataItemTypeTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/DataItems/DataItemTypeTests.cs new file mode 100644 index 000000000..874f377a2 --- /dev/null +++ b/tests/MTConnect.NET-Common-Tests/Devices/DataItems/DataItemTypeTests.cs @@ -0,0 +1,208 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using MTConnect.Devices; +using MTConnect.Devices.DataItems; +using MTConnect.Tests.Common.TestHelpers; +using NUnit.Framework; + +namespace MTConnect.NET_Common_Tests.Devices.DataItems +{ + // Version-gated shape assertions for every DataItem type the v2.6 and + // v2.7 SysML XMI introduces. + // + // - XMI: https://github.com/mtconnect/mtconnect_sysml_model tags + // v2.6 (SHA 08185447bf86…): + // * AssetAddedDataItem — xmi:id _2024x_68e0225_1744799118784_270323_23376 + // * AssociatedAssetIdDataItem — xmi:id _2024x_68e0225_1744800465544_… + // * AssetChangedDataItem — description rewritten in v2.6 + // v2.7 (SHA 25796ac591bb…) — Observation Types package: + // * BindingState (Event), Depth (Event), FixtureAssetId (Event), + // SwingAngle (Event), SwingDiameter (Event), SwingRadius (Event), + // TaskAssetId (Event), WaterHardness (Sample). + // - XSD: https://schemas.mtconnect.org/schemas/MTConnectStreams_2.6.xsd + // MTConnectStreams_2.7.xsd + // (each TypeId is encoded in the EventEnum / SampleEnum + // enumerations.) + // - Prose: MTConnect Standard Part_2.0_Streams_v2.6 section 11.5 "Asset + // events" (asset-event split rationale); + // Part_2.0_Streams_v2.7 sections 11/13 "Event/Sample types" + // (v2.7 additions). + // + // Every fixture below is matrix-parameterised over + // MTConnectVersionMatrix.All per plan Design Decision D1 + // (2026-08-19). Assume.That gates each assertion to versions where + // the spec introduced the type; rows below the floor surface as + // Inconclusive in the test explorer. + /// Pins the behavior expressed by the test name: data item type tests. + [TestFixture] + public class DataItemTypeTests + { + // Source: XMI v2.6 UML class `AssetAddedDataItem`; XSD v2.6 enum + // `EventEnum` value `ASSET_ADDED`. + /// Pins the behavior expressed by the test name: asset added data item constructs with event metadata. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AssetAddedDataItem_constructs_with_event_metadata(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version26), + "AssetAddedDataItem was introduced in MTConnect v2.6."); + + var d = new AssetAddedDataItem(); + Assert.That(d.Type, Is.EqualTo("ASSET_ADDED")); + Assert.That(d.Name, Is.EqualTo("assetAdded")); + Assert.That(d.Category, Is.EqualTo(DataItemCategory.EVENT)); + Assert.That(AssetAddedDataItem.TypeId, Is.EqualTo("ASSET_ADDED")); + Assert.That(AssetAddedDataItem.NameId, Is.EqualTo("assetAdded")); + Assert.That(AssetAddedDataItem.CategoryId, Is.EqualTo(DataItemCategory.EVENT)); + } + + // Source: XMI v2.6 — `DataItem.id` formation rule via parent device. + /// Pins the behavior expressed by the test name: asset added data item with device id produces qualified id. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AssetAddedDataItem_with_deviceId_produces_qualified_id(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version26), + "AssetAddedDataItem was introduced in MTConnect v2.6."); + + var d = new AssetAddedDataItem("dev01"); + Assert.That(d.Id, Is.Not.Null.And.Not.Empty); + Assert.That(d.Id, Does.Contain("dev01")); + Assert.That(d.Type, Is.EqualTo("ASSET_ADDED")); + } + + // Source: XMI v2.6 UML class `AssociatedAssetIdDataItem`; XSD v2.6 + // EventEnum value `ASSOCIATED_ASSET_ID`. + /// Pins the behavior expressed by the test name: associated asset id data item constructs with event metadata. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AssociatedAssetIdDataItem_constructs_with_event_metadata(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version26), + "AssociatedAssetIdDataItem was introduced in MTConnect v2.6."); + + var d = new AssociatedAssetIdDataItem(); + Assert.That(d.Type, Is.EqualTo(AssociatedAssetIdDataItem.TypeId)); + Assert.That(d.Name, Is.EqualTo(AssociatedAssetIdDataItem.NameId)); + Assert.That(d.Category, Is.EqualTo(AssociatedAssetIdDataItem.CategoryId)); + Assert.That(AssociatedAssetIdDataItem.TypeId, Is.EqualTo("ASSOCIATED_ASSET_ID")); + Assert.That(AssociatedAssetIdDataItem.CategoryId, Is.EqualTo(DataItemCategory.EVENT)); + } + + // Source: XMI v2.6 — generalization of `AssetAddedDataItem` is `DataItem`. + /// Pins the behavior expressed by the test name: asset added data item inherits from data item. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AssetAddedDataItem_inherits_from_DataItem(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version26), + "AssetAddedDataItem was introduced in MTConnect v2.6."); + + Assert.That(typeof(AssetAddedDataItem).BaseType, Is.EqualTo(typeof(DataItem))); + } + + // Source: XMI v2.6 — generalization of `AssociatedAssetIdDataItem` is `DataItem`. + /// Pins the behavior expressed by the test name: associated asset id data item inherits from data item. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AssociatedAssetIdDataItem_inherits_from_DataItem(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version26), + "AssociatedAssetIdDataItem was introduced in MTConnect v2.6."); + + Assert.That(typeof(AssociatedAssetIdDataItem).BaseType, Is.EqualTo(typeof(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 behavior expressed by the test name: asset changed data item description narrowed. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void AssetChangedDataItem_description_narrowed(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version26), + "The narrowed description shipped in MTConnect v2.6."); + + Assert.That(AssetChangedDataItem.DescriptionText, + Is.EqualTo("AssetId of the Asset that has been changed."), + "AssetChangedDataItem description must reflect the v2.6 split " + + "where 'added' moved to AssetAddedDataItem"); + } + + // Combined enumeration of the (Type, ExpectedTypeId, ExpectedCategory) + // triples for the v2.7 DataItem additions, cross-multiplied with + // MTConnectVersionMatrix.All so each row exercises the full 17-way + // version matrix. Assume.That gates every row to v2.7. + // + // Categories match what the v2.7 SysML XMI declares — the spec + // 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. + /// Enumerates the (type, expected type id, expected category, version) rows for the v2.7 DataItem sweep. + /// The parametric matrix. + public static IEnumerable V27DataItemCases() + { + var kinds = new (Type Type, string TypeId, DataItemCategory Category)[] + { + (typeof(BindingStateDataItem), "BINDING_STATE", DataItemCategory.EVENT), + (typeof(DepthDataItem), "DEPTH", DataItemCategory.EVENT), + (typeof(FixtureAssetIdDataItem), "FIXTURE_ASSET_ID", DataItemCategory.EVENT), + (typeof(SwingAngleDataItem), "SWING_ANGLE", DataItemCategory.EVENT), + (typeof(SwingDiameterDataItem), "SWING_DIAMETER", DataItemCategory.EVENT), + (typeof(SwingRadiusDataItem), "SWING_RADIUS", DataItemCategory.EVENT), + (typeof(TaskAssetIdDataItem), "TASK_ASSET_ID", DataItemCategory.EVENT), + (typeof(WaterHardnessDataItem), "WATER_HARDNESS", DataItemCategory.SAMPLE), + }; + + foreach (var v in MTConnectVersionMatrix.All) + { + foreach (var (type, typeId, category) in kinds) + { + yield return new TestCaseData(type, typeId, category, v) + .SetName($"DataItem_constructs_with_correct_metadata({type.Name},{typeId},{category},{v})"); + } + } + } + + // Source: XMI v2.7 Observation Types package (each entry above). + /// Pins the behavior expressed by the test name: data item constructs with correct metadata. + /// The data item type. + /// The expected type id. + /// The expected category. + /// The MTConnect Standard version under test. + [TestCaseSource(nameof(V27DataItemCases))] + public void DataItem_constructs_with_correct_metadata( + Type dataItemType, + string expectedTypeId, + DataItemCategory expectedCategory, + Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "These DataItem types were introduced in MTConnect v2.7."); + + // Wrap with Assert.DoesNotThrow so a missing parameterless ctor + // surfaces as a clear NUnit failure with the offending type + // name rather than a bare MissingMethodException. + object? instance = null; + Assert.DoesNotThrow(() => instance = Activator.CreateInstance(dataItemType), + $"{dataItemType.Name} should have a public parameterless constructor"); + Assert.That(instance, Is.Not.Null); + Assert.That(instance, Is.InstanceOf()); + + var di = (DataItem)instance!; + Assert.That(di.Type, Is.EqualTo(expectedTypeId), + $"{dataItemType.Name}.Type should be the spec TypeId"); + Assert.That(di.Category, Is.EqualTo(expectedCategory), + $"{dataItemType.Name}.Category should be {expectedCategory}"); + + var typeIdConst = dataItemType.GetField("TypeId", + System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)?.GetRawConstantValue(); + Assert.That(typeIdConst, Is.EqualTo(expectedTypeId), + $"{dataItemType.Name}.TypeId static const should match the spec TypeId"); + } + } +} diff --git a/tests/MTConnect.NET-Common-Tests/Devices/DataItems/StructuredRepresentationClassifierTests.cs b/tests/MTConnect.NET-Common-Tests/Devices/DataItems/StructuredRepresentationClassifierTests.cs index 2f824b523..b725d481b 100644 --- a/tests/MTConnect.NET-Common-Tests/Devices/DataItems/StructuredRepresentationClassifierTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Devices/DataItems/StructuredRepresentationClassifierTests.cs @@ -24,13 +24,10 @@ namespace MTConnect.Tests.Common.Devices.DataItems /// v2.7. The result class for each pinned DataItem generalizes /// from the abstract DataSet class: /// ALARM_LIMITS -> AlarmLimitResult -> DataSet - /// ALARM_LIMIT -> AlarmLimitResult -> DataSet /// CONTROL_LIMITS -> ControlLimitsResult -> DataSet - /// CONTROL_LIMIT -> ControlLimitsResult -> DataSet /// LOCATION_ADDRESS -> AddressResult -> DataSet /// LOCATION_SPATIAL_GEOGRAPHIC -> GeographicLocationResult -> DataSet /// SPECIFICATION_LIMITS -> SpecificationLimitsResult -> DataSet - /// SPECIFICATION_LIMIT -> SpecificationLimitResult -> DataSet /// SENSOR_ATTACHMENT -> SensorAttachmentResult -> DataSet /// - XSD: https://schemas.mtconnect.org/schemas/MTConnectStreams_2.7.xsd /// declares the matching DataSet-substitution observation @@ -38,6 +35,13 @@ namespace MTConnect.Tests.Common.Devices.DataItems /// that pair with each of the DataItems below. /// - Reference implementation: cppagent v2.7.0.7 emits these /// types as DATA_SET observations (not TABLE). + /// + /// The now-obsolete singular predecessors (ALARM_LIMIT, CONTROL_LIMIT, + /// SPECIFICATION_LIMIT - deprecated in v2.5) shared their result + /// class (or an equally DataSet-rooted one) with the plural + /// replacement pinned below, so the generalization-chain walk they + /// exercised is still covered without referencing the obsolete + /// types directly. /// [TestFixture] [Category("StructuredRepresentationClassifier")] @@ -52,15 +56,6 @@ 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() - { - Assert.That( - AlarmLimitDataItem.DefaultRepresentation, - 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() @@ -70,15 +65,6 @@ 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() - { - Assert.That( - ControlLimitDataItem.DefaultRepresentation, - 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() @@ -106,15 +92,6 @@ 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() - { - Assert.That( - SpecificationLimitDataItem.DefaultRepresentation, - 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() diff --git a/tests/MTConnect.NET-Common-Tests/DryGenerator/AssertionParityTests.cs b/tests/MTConnect.NET-Common-Tests/DryGenerator/AssertionParityTests.cs new file mode 100644 index 000000000..f51dcb058 --- /dev/null +++ b/tests/MTConnect.NET-Common-Tests/DryGenerator/AssertionParityTests.cs @@ -0,0 +1,173 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using NUnit.Framework; + +namespace MTConnect.NET_Common_Tests.DryGenerator +{ + // Parity guard for the DRY-generator campaign's Phase 1 migration. + // + // The migration collapses the per-version fixture family under + // tests/MTConnect.NET-Common-Tests/V2_6_V2_7/ + // into single-topic fixtures at their canonical location: + // tests/MTConnect.NET-Common-Tests/Devices/DataItems/DataItemTypeTests.cs + // tests/MTConnect.NET-Common-Tests/Devices/Components/ComponentTests.cs + // tests/MTConnect.NET-Common-Tests/Devices/Configurations/ConfigurationTests.cs + // tests/MTConnect.NET-Common-Tests/Observations/SampleObservationTests.cs + // tests/MTConnect.NET-Common-Tests/Enums/EnumArmTests.cs + // tests/MTConnect.NET-Common-Tests/MTConnectVersionsTests.cs + // + // Every assertion the pre-migration fixtures carried MUST re-appear at + // its post-migration home. This fixture asserts that invariant by + // walking a hardcoded baseline snapshot of the 34 pre-migration + // [Test] / [TestCase] method entries (captured 2026-08-19 from + // extra-files.user/plans/dry-generator-phase0/baseline-assertions-2026-08-19.txt) + // against the live reflection view of the test assembly. + // + // States: + // - RED (pre-migration): the new topic fixtures do not exist yet; + // the baseline entries have no post-migration home. Every entry + // surfaces as a missing target. + // - GREEN (post-migration): every baseline entry resolves to a + // method that carries [Test] / [TestCase] / [TestCaseSource] and + // lives OUTSIDE the deprecated V2_6_V2_7 namespace. The V2_6_V2_7 + // folder itself is deleted; PerVersionFolderProhibitionTests + // enforces the deletion permanently. + // + // Renames are declared inline via MigrationMap below. The gitignored + // extra-files.user/plans/dry-generator-phase0/renames.tsv artefact is a + // human-facing audit trail; the assertion source of truth lives in this + // fixture so the test is portable across clones. + /// Pins the behavior expressed by the test name: assertion parity tests. + [TestFixture] + public class AssertionParityTests + { + // Every pre-migration method's expected post-migration name. + // Identity entries (OldMethod == NewMethod) migrate under the same + // name; renames carry a NewMethod that strips the `_in_v2_6` + // suffix or the `V2_7_` prefix, since the version is now a + // property of the [TestCaseSource(MTConnectVersionMatrix.All)] + // matrix rather than encoded in the method name. + private static readonly (string OldFile, string OldMethod, string NewMethod)[] MigrationMap = + { + // V2_6ComponentAndEnumTests.cs (3 methods) + ("V2_6ComponentAndEnumTests.cs", "CuttingTorchComponent_constructs_with_correct_type", "CuttingTorchComponent_constructs_with_correct_type"), + ("V2_6ComponentAndEnumTests.cs", "ElectrodeComponent_constructs_with_correct_type", "ElectrodeComponent_constructs_with_correct_type"), + ("V2_6ComponentAndEnumTests.cs", "MediaType_QIF_MBD_value_present_in_v2_6", "MediaType_QIF_MBD_value_present"), + + // V2_6DataItemTypeTests.cs (6 methods) + ("V2_6DataItemTypeTests.cs", "AssetAddedDataItem_constructs_with_event_metadata", "AssetAddedDataItem_constructs_with_event_metadata"), + ("V2_6DataItemTypeTests.cs", "AssetAddedDataItem_with_deviceId_produces_qualified_id", "AssetAddedDataItem_with_deviceId_produces_qualified_id"), + ("V2_6DataItemTypeTests.cs", "AssociatedAssetIdDataItem_constructs_with_event_metadata", "AssociatedAssetIdDataItem_constructs_with_event_metadata"), + ("V2_6DataItemTypeTests.cs", "AssetAddedDataItem_inherits_from_DataItem", "AssetAddedDataItem_inherits_from_DataItem"), + ("V2_6DataItemTypeTests.cs", "AssociatedAssetIdDataItem_inherits_from_DataItem", "AssociatedAssetIdDataItem_inherits_from_DataItem"), + ("V2_6DataItemTypeTests.cs", "AssetChangedDataItem_description_narrowed_in_v2_6", "AssetChangedDataItem_description_narrowed"), + + // V2_7DataItemTypeTests.cs (1 method, 8 [TestCase] rows) + ("V2_7DataItemTypeTests.cs", "V2_7_DataItem_constructs_with_correct_metadata", "DataItem_constructs_with_correct_metadata"), + + // MTConnectVersionsTests.cs (5 methods — kept plain [Test] since + // these test constant-value invariants, not per-version behavior) + ("MTConnectVersionsTests.cs", "Version26_constant_equals_2_6", "Version26_constant_equals_2_6"), + ("MTConnectVersionsTests.cs", "Version27_constant_equals_2_7", "Version27_constant_equals_2_7"), + ("MTConnectVersionsTests.cs", "Max_equals_Version27", "Max_equals_Version27"), + ("MTConnectVersionsTests.cs", "Every_published_version_constant_is_distinct_and_monotonic", "Every_published_version_constant_is_distinct_and_monotonic"), + ("MTConnectVersionsTests.cs", "Version19_field_does_not_exist", "Version19_field_does_not_exist"), + + // V2_7ComponentTests.cs (2 methods) + ("V2_7ComponentTests.cs", "PinToolComponent_constructs_with_correct_type", "PinToolComponent_constructs_with_correct_type"), + ("V2_7ComponentTests.cs", "ToolHolderComponent_constructs_with_correct_type", "ToolHolderComponent_constructs_with_correct_type"), + + // V2_7ConfigurationDataSetTests.cs (16 methods) + ("V2_7ConfigurationDataSetTests.cs", "DataSet_base_constructs_and_implements_IDataSet", "DataSet_base_constructs_and_implements_IDataSet"), + ("V2_7ConfigurationDataSetTests.cs", "AxisDataSet_has_xyz_fields_and_implements_IDataSet", "AxisDataSet_has_xyz_fields_and_implements_IDataSet"), + ("V2_7ConfigurationDataSetTests.cs", "OriginDataSet_has_xyz_fields_and_implements_IDataSet", "OriginDataSet_has_xyz_fields_and_implements_IDataSet"), + ("V2_7ConfigurationDataSetTests.cs", "RotationDataSet_has_abc_fields_and_implements_IDataSet", "RotationDataSet_has_abc_fields_and_implements_IDataSet"), + ("V2_7ConfigurationDataSetTests.cs", "ScaleDataSet_implements_IDataSet", "ScaleDataSet_implements_IDataSet"), + ("V2_7ConfigurationDataSetTests.cs", "TranslationDataSet_implements_IDataSet", "TranslationDataSet_implements_IDataSet"), + ("V2_7ConfigurationDataSetTests.cs", "Axis_inherits_AbstractAxis_and_constructs", "Axis_inherits_AbstractAxis_and_constructs"), + ("V2_7ConfigurationDataSetTests.cs", "Origin_inherits_AbstractOrigin", "Origin_inherits_AbstractOrigin"), + ("V2_7ConfigurationDataSetTests.cs", "Rotation_inherits_AbstractRotation", "Rotation_inherits_AbstractRotation"), + ("V2_7ConfigurationDataSetTests.cs", "Scale_inherits_AbstractScale", "Scale_inherits_AbstractScale"), + ("V2_7ConfigurationDataSetTests.cs", "Translation_inherits_AbstractTranslation", "Translation_inherits_AbstractTranslation"), + ("V2_7ConfigurationDataSetTests.cs", "AbstractAxis_is_abstract", "AbstractAxis_is_abstract"), + ("V2_7ConfigurationDataSetTests.cs", "AbstractOrigin_is_abstract", "AbstractOrigin_is_abstract"), + ("V2_7ConfigurationDataSetTests.cs", "AbstractRotation_is_abstract", "AbstractRotation_is_abstract"), + ("V2_7ConfigurationDataSetTests.cs", "AbstractScale_is_abstract", "AbstractScale_is_abstract"), + ("V2_7ConfigurationDataSetTests.cs", "AbstractTranslation_is_abstract", "AbstractTranslation_is_abstract"), + + // V2_7SampleObservationTests.cs (1 method) + ("V2_7SampleObservationTests.cs", "WaterHardness_sample_observation_round_trip", "WaterHardness_sample_observation_round_trip"), + }; + + /// Pins the invariant: every baseline assertion has a post-migration home. + [Test] + public void Every_baseline_assertion_has_a_post_migration_home() + { + var postMigrationMethods = EnumeratePostMigrationTestMethods(); + var missing = new List(); + + foreach (var (oldFile, oldMethod, newMethod) in MigrationMap) + { + if (!postMigrationMethods.Contains(newMethod)) + { + missing.Add($"{oldFile}::{oldMethod} -> {newMethod}"); + } + } + + Assert.That(missing, Is.Empty, + "Baseline assertions missing a post-migration home:\n " + + string.Join("\n ", missing)); + } + + /// Pins the invariant: the migration map covers every baseline entry. + [Test] + public void Migration_map_covers_the_full_baseline_of_34_entries() + { + // Guard against silent shrinkage of the map itself. The Phase 0 + // baseline captured exactly 34 [Test] / [TestCase] method + // entries; if a future edit trims the map below that floor, the + // parity guard is inspecting less than the full baseline and + // this fixture must fail loudly. + Assert.That(MigrationMap.Length, Is.EqualTo(34), + "MigrationMap has drifted from the 34-entry baseline captured " + + "on 2026-08-19. Re-verify against " + + "extra-files.user/plans/dry-generator-phase0/baseline-assertions-2026-08-19.txt " + + "before editing."); + } + + // Reflect over the test assembly and return every method name that + // carries [Test], [TestCase], or [TestCaseSource] and lives OUTSIDE + // the deprecated V2_6_V2_7 namespace. The name-only granularity + // matches the plan's Phase 1.4 assertion-diff shape. + private static ISet EnumeratePostMigrationTestMethods() + { + var assembly = typeof(AssertionParityTests).Assembly; + return assembly.GetTypes() + .Where(t => t.Namespace != null + && !t.Namespace.Contains("V2_6_V2_7", StringComparison.Ordinal)) + .SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.Instance)) + .Where(HasNUnitTestAttribute) + .Select(m => m.Name) + .ToHashSet(StringComparer.Ordinal); + } + + private static bool HasNUnitTestAttribute(MethodInfo method) + { + foreach (var attribute in method.GetCustomAttributes(inherit: false)) + { + if (attribute is TestAttribute + || attribute is TestCaseAttribute + || attribute is TestCaseSourceAttribute) + { + return true; + } + } + return false; + } + } +} diff --git a/tests/MTConnect.NET-Common-Tests/DryGenerator/PerVersionFolderProhibitionTests.cs b/tests/MTConnect.NET-Common-Tests/DryGenerator/PerVersionFolderProhibitionTests.cs new file mode 100644 index 000000000..c6c08c3ba --- /dev/null +++ b/tests/MTConnect.NET-Common-Tests/DryGenerator/PerVersionFolderProhibitionTests.cs @@ -0,0 +1,199 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using NUnit.Framework; + +namespace MTConnect.NET_Common_Tests.DryGenerator +{ + // Permanent regression guard against the deprecated per-version + // fixture-folder convention. Fires RED if any new V/ directory + // or V*Tests fixture class returns to + // tests/MTConnect.NET-Common-Tests/. + // + // Enforcement rules (plan §"Single-test-file-per-topic convention"): + // * No V/ directory under tests/MTConnect.NET-Common-Tests/. + // * No fixture class matching the V*Tests pattern in the + // assembly, except historical anchors listed in HistoricalAnchors. + // * No fixture file name matching V*Tests.cs on disk. + // + // Historical anchors (e.g. CppAgentParityWorkflowTests pinned to + // Version25) are NOT migrated — they document a deliberate, + // permanent pin. Add such classes to HistoricalAnchors with a + // rationale comment before the entry. + /// Pins the behavior expressed by the test name: per version folder prohibition tests. + [TestFixture] + public class PerVersionFolderProhibitionTests + { + // Fixture full-class-names allowed to keep a V* naming + // convention (historical anchors that document a permanent + // version pin). Each entry must include a rationale comment. + private static readonly HashSet HistoricalAnchors = new(StringComparer.Ordinal) + { + // No historical anchors at HEAD — this list exists so that a + // future contributor introducing a deliberately-pinned + // fixture (e.g. CppAgentParityWorkflowTests pinned to a + // specific version for spec-fidelity reasons) can document + // the pin here rather than trip the guard. + }; + + /// Pins the invariant: no V-N-M subdirectory exists under the test project. + [Test] + public void No_per_version_directory_exists_under_tests_MTConnect_NET_Common_Tests() + { + var testsRoot = LocateTestProjectRoot(); + var offenders = Directory.EnumerateDirectories( + testsRoot, + "V*", + SearchOption.AllDirectories) + .Where(path => !IsUnderIgnoredDirectory(path)) + .Where(IsPerVersionDirectoryName) + .Select(path => Path.GetRelativePath(testsRoot, path)) + .OrderBy(x => x, StringComparer.Ordinal) + .ToList(); + + Assert.That(offenders, Is.Empty, + "Per-version fixture directories (V/) are deprecated by the " + + "DRY-generator campaign. Migrate the fixtures into a topic-first " + + "layout (Devices/DataItems/, Devices/Components/, etc.) with " + + "matrix-parameterised version-gated assertions. Offending directories:\n " + + string.Join("\n ", offenders)); + } + + /// Pins the invariant: no V-N-M fixture file lives on disk under the test project. + [Test] + public void No_per_version_fixture_file_exists_under_tests_MTConnect_NET_Common_Tests() + { + var testsRoot = LocateTestProjectRoot(); + var offenders = Directory.EnumerateFiles( + testsRoot, + "V*Tests.cs", + SearchOption.AllDirectories) + .Where(path => !IsUnderIgnoredDirectory(path)) + .Where(path => IsPerVersionFileName(Path.GetFileName(path))) + .Select(path => Path.GetRelativePath(testsRoot, path)) + .OrderBy(x => x, StringComparer.Ordinal) + .ToList(); + + Assert.That(offenders, Is.Empty, + "Per-version fixture files (V*Tests.cs) are deprecated by the " + + "DRY-generator campaign. Rename to a topic-first name (e.g. " + + "V2_7DataItemTypeTests.cs -> DataItemTypeTests.cs). Offending files:\n " + + string.Join("\n ", offenders)); + } + + /// Pins the invariant: no V-N-M fixture class exists in the test assembly. + [Test] + public void No_per_version_fixture_class_exists_in_the_test_assembly() + { + var assembly = typeof(PerVersionFolderProhibitionTests).Assembly; + var offenders = assembly.GetTypes() + .Where(t => t.IsPublic || t.IsNestedPublic) + .Where(t => t.GetCustomAttribute() != null) + .Where(t => IsPerVersionClassName(t.Name)) + .Where(t => !HistoricalAnchors.Contains(t.FullName ?? t.Name)) + .Select(t => t.FullName ?? t.Name) + .OrderBy(x => x, StringComparer.Ordinal) + .ToList(); + + Assert.That(offenders, Is.Empty, + "Per-version fixture classes (V*Tests) are deprecated by the " + + "DRY-generator campaign. If a class is a deliberate historical anchor " + + "(e.g. a permanent version pin for spec-fidelity reasons), add its " + + "full name to PerVersionFolderProhibitionTests.HistoricalAnchors with " + + "a rationale comment. Offending classes:\n " + + string.Join("\n ", offenders)); + } + + // Locate the test project's source root by walking up from the test + // binary's directory. The test project's .csproj lives at the root. + // This walker is resilient to being invoked from bin/Debug/net8.0/, + // bin/Release/net8.0/, or a runsettings-overridden directory. + private static string LocateTestProjectRoot() + { + var dir = new DirectoryInfo(TestContext.CurrentContext.TestDirectory); + while (dir != null) + { + if (File.Exists(Path.Combine(dir.FullName, "MTConnect.NET-Common-Tests.csproj"))) + { + return dir.FullName; + } + dir = dir.Parent; + } + throw new InvalidOperationException( + "Could not locate MTConnect.NET-Common-Tests.csproj from test directory: " + + TestContext.CurrentContext.TestDirectory); + } + + // Match V_[__...] directory names — + // e.g. V2_6, V2_6_V2_7, V1_8. Any leading-V-then-underscored-digits + // sequence counts. + private static bool IsPerVersionDirectoryName(string absolutePath) + { + var name = Path.GetFileName(absolutePath); + return LooksLikePerVersionToken(name); + } + + // Match V_*Tests.cs — the file naming convention + // the migration retires. Excludes anything without the V-prefix + // digit-underscored pattern. + private static bool IsPerVersionFileName(string fileName) + { + if (!fileName.EndsWith("Tests.cs", StringComparison.Ordinal)) + { + return false; + } + // Strip ".cs" and the "Tests" suffix; the head must still + // start with a per-version token. + var head = fileName.Substring(0, fileName.Length - "Tests.cs".Length); + return LooksLikePerVersionToken(head); + } + + // Match V_*Tests class names for the assembly + // reflection sweep. + private static bool IsPerVersionClassName(string className) + { + if (!className.EndsWith("Tests", StringComparison.Ordinal)) + { + return false; + } + var head = className.Substring(0, className.Length - "Tests".Length); + return LooksLikePerVersionToken(head); + } + + // A per-version token starts with 'V', then one-or-more digits, + // then an underscore, then one-or-more digits, then any suffix + // (which may include additional V_ segments). + private static bool LooksLikePerVersionToken(string head) + { + if (string.IsNullOrEmpty(head) || head[0] != 'V') + { + return false; + } + int i = 1; + // one or more digits after V + if (i >= head.Length || !char.IsDigit(head[i])) return false; + while (i < head.Length && char.IsDigit(head[i])) i++; + // required underscore separator + if (i >= head.Length || head[i] != '_') return false; + i++; + // one or more digits after the underscore + if (i >= head.Length || !char.IsDigit(head[i])) return false; + return true; + } + + // The recursive directory walker crosses into bin/ and obj/ under + // Debug builds; filter those out so the guard reflects the source + // tree rather than build artefacts. + private static bool IsUnderIgnoredDirectory(string absolutePath) + { + var normalised = absolutePath.Replace('\\', '/'); + return normalised.Contains("/bin/", StringComparison.Ordinal) + || normalised.Contains("/obj/", StringComparison.Ordinal); + } + } +} diff --git a/tests/MTConnect.NET-Common-Tests/DryGenerator/TopicFixtureCoverageTests.cs b/tests/MTConnect.NET-Common-Tests/DryGenerator/TopicFixtureCoverageTests.cs new file mode 100644 index 000000000..3aad7e304 --- /dev/null +++ b/tests/MTConnect.NET-Common-Tests/DryGenerator/TopicFixtureCoverageTests.cs @@ -0,0 +1,207 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using NUnit.Framework; + +namespace MTConnect.NET_Common_Tests.DryGenerator +{ + // Phase 2.2 topic-fixture coverage guard (DRY-generator campaign plan + // §2.2 — "Extend RegeneratedTypesCoverageTests with per-topic coverage"). + // + // For every spec-anchor type migrated out of the deprecated per-version + // fixture family (tests/MTConnect.NET-Common-Tests/V2_6_V2_7/) the + // canonical topic-fixture file MUST name the type at least once. This + // is a permanent guard: a future edit that renames a topic fixture or + // deletes an anchor assertion without a replacement fires RED here. + // + // Complementarity with the sibling guards: + // - AssertionParityTests holds the 34-entry method-name migration + // map and asserts every entry resolves to a live [Test] method. + // It does NOT check that the resolved method actually references + // the anchor type (a rename that changed the fixture location AND + // replaced the assertion body would slip past a name-only guard). + // - PerVersionFolderProhibitionTests asserts no V/ topology + // regrowth. It says nothing about coverage of anchor types. + // - TopicFixtureCoverageTests (this file) asserts every anchor type + // name appears in its designated topic-fixture source file. This + // is the source-text cross-check the plan calls for. + // + // Source of truth for the anchor list: the migration renames.tsv + // artefact under extra-files.user/plans/dry-generator-phase0/ + // (gitignored — the tsv is the audit trail; the C# entries below + // are the assertion source). Every anchor type mentioned in a + // renames.tsv row lands here with its topic-fixture destination. + // + // Substring-match risk: the scan uses a whole-token regex + // (\b\b) so a shorter type name (e.g. Axis) does not falsely + // match a longer one (AxisDataSet, AbstractAxis). Comments inside the + // topic fixture count as valid mentions — the guard is that the type + // name is present in the source text, not that a specific attribute + // shape references it. + // + // Source authority: + // - SysML XMI: https://github.com/mtconnect/mtconnect_sysml_model + // (per-version tag). Every anchor type maps to a UML class that + // the SysML importer emits into MTConnect.NET-Common. + // - MTConnect Standard Part 2 — Devices Information Model / + // Part 3 — Streams / Part 4 — Assets. Defines the topic + // hierarchy the topic-fixture files mirror. + /// Pins the invariant: every migrated spec-anchor type is named in its designated topic-fixture source file. + [TestFixture] + public class TopicFixtureCoverageTests + { + // (anchor_type_name, topic_fixture_relative_path) pairs sourced + // verbatim from renames.tsv. New spec-version bumps append rows + // here alongside the topic-fixture edit; this map is the ONE + // place the anchor-set is versioned. + // + // Path is relative to the tests/MTConnect.NET-Common-Tests/ + // project root. Forward slashes match POSIX conventions; the + // path resolver below normalises for Windows. + private static readonly (string AnchorType, string TopicFixtureRelativePath)[] TopicAnchors = + { + // --- Component types (2 v2.6, 2 v2.7) --------------------- + ("CuttingTorchComponent", "Devices/Components/ComponentTests.cs"), + ("ElectrodeComponent", "Devices/Components/ComponentTests.cs"), + ("PinToolComponent", "Devices/Components/ComponentTests.cs"), + ("ToolHolderComponent", "Devices/Components/ComponentTests.cs"), + + // --- DataItem types (v2.6 anchor set) --------------------- + ("AssetAddedDataItem", "Devices/DataItems/DataItemTypeTests.cs"), + ("AssociatedAssetIdDataItem", "Devices/DataItems/DataItemTypeTests.cs"), + ("AssetChangedDataItem", "Devices/DataItems/DataItemTypeTests.cs"), + + // --- Configuration DataSet types (v2.7 anchor set) -------- + ("DataSet", "Devices/Configurations/ConfigurationTests.cs"), + ("AxisDataSet", "Devices/Configurations/ConfigurationTests.cs"), + ("OriginDataSet", "Devices/Configurations/ConfigurationTests.cs"), + ("RotationDataSet", "Devices/Configurations/ConfigurationTests.cs"), + ("ScaleDataSet", "Devices/Configurations/ConfigurationTests.cs"), + ("TranslationDataSet", "Devices/Configurations/ConfigurationTests.cs"), + ("AbstractAxis", "Devices/Configurations/ConfigurationTests.cs"), + ("AbstractOrigin", "Devices/Configurations/ConfigurationTests.cs"), + ("AbstractRotation", "Devices/Configurations/ConfigurationTests.cs"), + ("AbstractScale", "Devices/Configurations/ConfigurationTests.cs"), + ("AbstractTranslation", "Devices/Configurations/ConfigurationTests.cs"), + + // --- Sample observation (v2.7 anchor) --------------------- + ("WaterHardness", "Observations/SampleObservationTests.cs"), + + // --- Enum arm (v2.6 anchor) ------------------------------- + ("MediaType", "Enums/EnumArmTests.cs"), + ("QIF_MBD", "Enums/EnumArmTests.cs"), + + // --- MTConnectVersions constants (v2.6/v2.7 anchors) ------ + ("Version26", "MTConnectVersionsTests.cs"), + ("Version27", "MTConnectVersionsTests.cs"), + }; + + /// Produces one test-case row per (anchor_type, topic_fixture) pair. + /// Enumeration of NUnit TestCaseData rows keyed by anchor type name. + public static IEnumerable Anchors() + { + foreach (var (anchorType, topicFixtureRelativePath) in TopicAnchors) + { + yield return new TestCaseData(anchorType, topicFixtureRelativePath) + .SetName($"Topic_fixture_names_{anchorType}"); + } + } + + /// Pins the invariant: the designated topic fixture source references the anchor type by name at least once. + /// The spec-anchor type name (as it appears in generated C# sources). + /// Path to the topic-fixture file, relative to the test project root; forward-slash separator. + [Test] + [TestCaseSource(nameof(Anchors))] + public void Topic_fixture_source_references_anchor_type(string anchorType, string topicFixtureRelativePath) + { + var testsRoot = LocateTestProjectRoot(); + var absolutePath = Path.Combine(testsRoot, + topicFixtureRelativePath.Replace('/', Path.DirectorySeparatorChar)); + + Assert.That(File.Exists(absolutePath), Is.True, + $"Topic fixture file '{topicFixtureRelativePath}' is missing under '{testsRoot}'. " + + "The topic-first convention requires every anchor type to live in its " + + "canonical topic fixture; adding an anchor row to TopicAnchors and then " + + "renaming/deleting the target file is the failure mode this guard catches."); + + var source = File.ReadAllText(absolutePath); + // Whole-word match so that a shorter anchor (e.g. Axis) does not + // spuriously match a longer type name (AbstractAxis, AxisDataSet). + var pattern = new Regex($@"\b{Regex.Escape(anchorType)}\b", RegexOptions.CultureInvariant); + Assert.That(pattern.IsMatch(source), Is.True, + $"Topic fixture '{topicFixtureRelativePath}' does not reference the anchor " + + $"type '{anchorType}'. The DRY-generator Phase 1 migration pinned this " + + $"type at this topic-fixture home; a coverage-parity regression happens when " + + "the anchor is silently removed. Restore the assertion (or move the anchor " + + "row in TopicFixtureCoverageTests.TopicAnchors to a different topic fixture " + + "AND leave a rationale) before landing the change."); + } + + /// Pins the smoke-invariant: the TopicAnchors map does not silently shrink below the migrated baseline. + [Test] + public void TopicAnchors_covers_at_least_the_full_migrated_baseline() + { + // The Phase 1 migration surfaced 23 distinct anchor types across + // six topic fixtures (4 Components + 3 DataItems + 11 Configuration + // + 1 WaterHardness + 2 Enum + 2 Version). The map above + // enumerates them explicitly. A future edit that changes the + // anchor list must land alongside a rationale in the topic + // fixture AND update this pinned count with the same rationale. + // Exact-equality matches the AssertionParityTests pattern (which + // pins the migration map at exactly 34) so a silent drop of one + // row cannot slip past a "≥ baseline" smoke floor. + Assert.That(TopicAnchors.Length, Is.EqualTo(23), + $"TopicAnchors is at {TopicAnchors.Length} entries — the Phase 1 " + + "migration baseline is exactly 23 entries. Restore the anchor rows " + + "or, if the change is intentional, update this pinned count with a " + + "rationale that cross-references the topic fixture change."); + } + + /// Pins the smoke-invariant: every distinct topic fixture named in TopicAnchors is present on disk. + [Test] + public void Every_topic_fixture_named_in_TopicAnchors_exists_on_disk() + { + var testsRoot = LocateTestProjectRoot(); + var missing = TopicAnchors + .Select(row => row.TopicFixtureRelativePath) + .Distinct(StringComparer.Ordinal) + .Where(rel => !File.Exists(Path.Combine(testsRoot, + rel.Replace('/', Path.DirectorySeparatorChar)))) + .OrderBy(x => x, StringComparer.Ordinal) + .ToList(); + + Assert.That(missing, Is.Empty, + "Topic fixture files named in TopicFixtureCoverageTests.TopicAnchors do not " + + "exist on disk. Restore the file or repoint the anchor rows to the " + + "correct topic-fixture home. Missing files:\n " + + string.Join("\n ", missing)); + } + + // Locate the test project's source root by walking up from the + // test binary's directory. The test project's .csproj lives at + // the root. This walker mirrors the pattern used in + // PerVersionFolderProhibitionTests so both guards resolve the + // same root under bin/Debug/net8.0/, bin/Release/net8.0/, and + // any runsettings-overridden test directory. + private static string LocateTestProjectRoot() + { + var dir = new DirectoryInfo(TestContext.CurrentContext.TestDirectory); + while (dir != null) + { + if (dir.EnumerateFiles("MTConnect.NET-Common-Tests.csproj").Any()) + return dir.FullName; + dir = dir.Parent; + } + + throw new InvalidOperationException( + "Could not locate MTConnect.NET-Common-Tests.csproj by walking up from " + + $"'{TestContext.CurrentContext.TestDirectory}'. TopicFixtureCoverageTests " + + "needs the source-tree root to open topic-fixture files for scanning."); + } + } +} diff --git a/tests/MTConnect.NET-Common-Tests/Enums/EnumArmTests.cs b/tests/MTConnect.NET-Common-Tests/Enums/EnumArmTests.cs new file mode 100644 index 000000000..6e0319941 --- /dev/null +++ b/tests/MTConnect.NET-Common-Tests/Enums/EnumArmTests.cs @@ -0,0 +1,46 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using MTConnect.Devices.Configurations; +using MTConnect.Tests.Common.TestHelpers; +using NUnit.Framework; + +namespace MTConnect.NET_Common_Tests.Enums +{ + // Version-gated enum-arm assertions. Each fixture pins a specific + // enum-value addition against its introducing MTConnect Standard + // version. + // + // - XMI: https://github.com/mtconnect/mtconnect_sysml_model tag list + // — every enum in this file traces to a UML enum extension in + // a specific v2.x tag. + // - XSD: https://schemas.mtconnect.org/schemas/MTConnectDevices_.xsd + // — the simpleType enumerations mirror the XMI additions. + // - Prose: MTConnect Standard Part_2.0_Devices/Streams — each enum + // extension is described in the part that owns the enum. + // + // Every fixture below is matrix-parameterised over + // MTConnectVersionMatrix.All per plan Design Decision D1 + // (2026-08-19); Assume.That gates each row to versions where the arm + // shipped. + /// Pins the behavior expressed by the test name: enum arm tests. + [TestFixture] + public class EnumArmTests + { + // Source: XMI v2.6 enum `MediaTypeEnum` member `QIF_MBD`. + // XSD v2.6 lists 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 behavior expressed by the test name: media type q i f m b d value present. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void MediaType_QIF_MBD_value_present(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version26), + "MediaType.QIF_MBD was introduced in MTConnect v2.6."); + + Assert.That(Enum.IsDefined(typeof(MediaType), "QIF_MBD"), Is.True); + } + } +} diff --git a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/MTConnectVersionsTests.cs b/tests/MTConnect.NET-Common-Tests/MTConnectVersionsTests.cs similarity index 77% rename from tests/MTConnect.NET-Common-Tests/V2_6_V2_7/MTConnectVersionsTests.cs rename to tests/MTConnect.NET-Common-Tests/MTConnectVersionsTests.cs index b4799004f..361f47ec8 100644 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/MTConnectVersionsTests.cs +++ b/tests/MTConnect.NET-Common-Tests/MTConnectVersionsTests.cs @@ -1,11 +1,24 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + using System; using System.Linq; using System.Reflection; using NUnit.Framework; -namespace MTConnect.NET_Common_Tests.V2_6_V2_7 +namespace MTConnect.NET_Common_Tests { - // Constants-level pins on `MTConnectVersions` for v2.6 and v2.7. + // Constants-level invariants on the MTConnectVersions class. + // + // These assertions test the shape of the MTConnectVersions type itself + // (constant values, distinctness, monotonicity, absence of forbidden + // constants). They are structural invariants of the type, NOT + // per-version behavioral gates, so they run as plain [Test] rather + // than under the [TestCaseSource(MTConnectVersionMatrix.All)] matrix + // that governs the behavioral fixtures elsewhere in this project. + // The plan's Design Decision D1 (2026-08-19) reserves the matrix for + // version-sensitive assertions; constant-value assertions live outside + // that scope. // // - XMI: https://github.com/mtconnect/mtconnect_sysml_model/tree/v2.6 // /v2.7 @@ -14,16 +27,16 @@ namespace MTConnect.NET_Common_Tests.V2_6_V2_7 // - XSD: https://schemas.mtconnect.org/schemas/MTConnectDevices_2.6.xsd // MTConnectDevices_2.7.xsd // (each XSD's targetNamespace embeds the version it represents.) - // - 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.) + // - 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. + // 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() @@ -48,8 +61,8 @@ public void Max_equals_Version27() } // Pin that the version list contains no 1.9 entry. - // Source: MTConnect Standard Part_1.0_Overview prose section 1 "Versioning"; - // confirmed by the absence of an XMI tag `v1.9` in + // Source: MTConnect Standard Part_1.0_Overview prose section 1 + // "Versioning"; 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. @@ -63,8 +76,8 @@ public void Every_published_version_constant_is_distinct_and_monotonic() .OrderBy(x => x.Value) .ToList(); - // 17 expected: v1.0-v1.8 (9) + v2.0-v2.7 (8). The Standard skipped v1.9 - // entirely so there is no Version19 constant. + // 17 expected: v1.0-v1.8 (9) + v2.0-v2.7 (8). The Standard skipped + // v1.9 entirely so there is no Version19 constant. Assert.That(versions.Count, Is.EqualTo(17), "Expected 17 version constants (v1.0-v1.8 plus v2.0-v2.7). Got " + string.Join(", ", versions.Select(x => x.Name))); diff --git a/tests/MTConnect.NET-Common-Tests/Observations/SampleObservationTests.cs b/tests/MTConnect.NET-Common-Tests/Observations/SampleObservationTests.cs new file mode 100644 index 000000000..afa53f55e --- /dev/null +++ b/tests/MTConnect.NET-Common-Tests/Observations/SampleObservationTests.cs @@ -0,0 +1,76 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using MTConnect.Devices; +using MTConnect.Devices.DataItems; +using MTConnect.Observations; +using MTConnect.Tests.Common.TestHelpers; +using NUnit.Framework; + +namespace MTConnect.NET_Common_Tests.Observations +{ + // Version-gated Sample-envelope round-trip assertions for the + // SAMPLE-category DataItems introduced across MTConnect Standard + // versions (currently WaterHardness at v2.7). + // + // - XMI: https://github.com/mtconnect/mtconnect_sysml_model @ tag v2.7 + // UML class `WaterHardnessDataItem` declares + // `category = SAMPLE`, MinimumVersion = v2.7. (Hardness is + // measured in mineral content of cooling water — used in + // machining workflows where coolant chemistry affects tool + // life.) + // - XSD: https://schemas.mtconnect.org/schemas/MTConnectStreams_2.7.xsd + // enum `SampleEnum` value `WATER_HARDNESS` is the + // sample-category element name on the wire. + // - Prose: MTConnect Standard Part_2.0_Streams_v2.7 section 11 + // "Sample observation types" — describes how SAMPLE-category + // observations carry continuous-numeric values reported at + // agent-defined intervals. + // + // Every fixture below is matrix-parameterised over + // MTConnectVersionMatrix.All per plan Design Decision D1 + // (2026-08-19). Assume.That gates each row to versions where the + // sample type shipped. + /// Pins the behavior expressed by the test name: sample observation tests. + [TestFixture] + public class SampleObservationTests + { + // Source: XMI v2.7 — `WaterHardness` is the only SAMPLE-category + // type introduced in v2.7 (the rest are EVENT). Tests the + // round-trip from creating a DataItem of this v2.7 type, attaching + // a SampleValueObservation, 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 behavior expressed by the test name: water hardness sample observation round trip. + /// The MTConnect Standard version under test. + [TestCaseSource(typeof(MTConnectVersionMatrix), nameof(MTConnectVersionMatrix.All))] + public void WaterHardness_sample_observation_round_trip(Version v) + { + Assume.That(v, Is.GreaterThanOrEqualTo(MTConnectVersions.Version27), + "WaterHardness was introduced in MTConnect v2.7."); + + var dataItem = new WaterHardnessDataItem("dev01"); + Assert.That(dataItem.Category, Is.EqualTo(DataItemCategory.SAMPLE)); + + var observation = new SampleValueObservation + { + DataItemId = dataItem.Id, + Result = "12.5", + Timestamp = System.DateTime.UtcNow, + Sequence = 42, + }; + + // Carrier preserves DataItemId so a downstream lookup of the + // type (DataItemId -> TypeId via the agent's DataItem registry) + // resolves back to WATER_HARDNESS. + Assert.That(observation.DataItemId, Is.EqualTo(dataItem.Id)); + Assert.That(observation.Result, Is.EqualTo("12.5")); + Assert.That(observation.Sequence, Is.EqualTo(42)); + + // The DataItem's Type field is what cppagent JSON / XML + // formatters look at when rendering the SAMPLE element name. + Assert.That(dataItem.Type, Is.EqualTo("WATER_HARDNESS")); + } + } +} diff --git a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedTypesCoverageTests.cs b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedTypesCoverageTests.cs index 7c26b1c78..57eff0392 100644 --- a/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedTypesCoverageTests.cs +++ b/tests/MTConnect.NET-Common-Tests/Reflection/RegeneratedTypesCoverageTests.cs @@ -215,8 +215,9 @@ public void Type_can_be_constructed(Type type) // Every public regenerated type's default ctor must execute at // least once so it counts as covered. This single parametric // case satisfies that for the class-with-bare-ctor case; ctors - // with arguments are covered by the typed fixtures under - // V2_6_V2_7/. + // with arguments are covered by the topic-first fixtures under + // Devices/DataItems/, Devices/Components/, Devices/Configurations/, + // Observations/, and Enums/ (Phase 1 DRY-generator consolidation). object? instance = null; Assert.DoesNotThrow( () => instance = Activator.CreateInstance(type), @@ -240,8 +241,9 @@ public void Type_round_trips_default_property_values(Type type) // // Properties without a public setter (read-only computed // properties such as Id) are skipped — the spec contract for - // those is "derived from other state", and the V2_6_V2_7 - // hand-written fixtures pin their semantics. + // those is "derived from other state", and the topic-first + // fixtures under Devices/DataItems/, Devices/Components/, + // Devices/Configurations/, and Observations/ pin their semantics. var instance = Activator.CreateInstance(type)!; foreach (var property in GetRoundTrippableProperties(type)) 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 deleted file mode 100644 index bcecc8dab..000000000 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_6ComponentAndEnumTests.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using MTConnect.Devices.Components; -using MTConnect.Devices.Configurations; -using NUnit.Framework; - -namespace MTConnect.NET_Common_Tests.V2_6_V2_7 -{ - // Pins the non-DataItem v2.6 surface: new Component subclasses + the - // MediaType enum's QIF_MBD addition. - // - // - XMI: mtconnect/mtconnect_sysml_model @ v2.6 (SHA 08185447bf86…) - // * UML class `CuttingTorch` — Component Types package - // * UML class `Electrode` — Component Types package - // * Enum `MediaTypeEnum` value `QIF_MBD` - // - XSD: schemas.mtconnect.org/schemas/MTConnectDevices_2.6.xsd - // (Component element list + MediaType simpleType enumeration) - // - 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() - { - var c = new CuttingTorchComponent(); - Assert.That(c.Type, Is.EqualTo("CuttingTorch")); - Assert.That(c.Name, Is.Null); - Assert.That(CuttingTorchComponent.TypeId, Is.EqualTo("CuttingTorch")); - Assert.That(CuttingTorchComponent.NameId, Is.EqualTo("cuttingTorch")); - } - - // 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() - { - var c = new ElectrodeComponent(); - Assert.That(c.Type, Is.EqualTo("Electrode")); - Assert.That(c.Name, Is.Null); - Assert.That(ElectrodeComponent.TypeId, Is.EqualTo("Electrode")); - Assert.That(ElectrodeComponent.NameId, Is.EqualTo("electrode")); - } - - // Source: XMI v2.6 enum `MediaTypeEnum` member `QIF_MBD`. XSD v2.6 lists - // 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() - { - Assert.That(Enum.IsDefined(typeof(MediaType), "QIF_MBD"), Is.True); - } - } -} 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 deleted file mode 100644 index 1919e9d1d..000000000 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_6DataItemTypeTests.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using MTConnect.Devices; -using MTConnect.Devices.DataItems; -using NUnit.Framework; - -namespace MTConnect.NET_Common_Tests.V2_6_V2_7 -{ - // Pins every DataItem type the v2.6 SysML XMI introduces. - // - // - XMI: mtconnect/mtconnect_sysml_model @ v2.6 (SHA 08185447bf86…) - // UML classes: - // * `AssetAddedDataItem` — xmi:id _2024x_68e0225_1744799118784_270323_23376 - // * `AssociatedAssetIdDataItem` — xmi:id _2024x_68e0225_1744800465544_… - // * `AssetChangedDataItem` — description rewritten in v2.6 - // - XSD: schemas.mtconnect.org/schemas/MTConnectStreams_2.6.xsd - // (the EVENT category for both new types is encoded in the - // MTConnectStreams XSD's enumerations.) - // - 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() - { - var d = new AssetAddedDataItem(); - Assert.That(d.Type, Is.EqualTo("ASSET_ADDED")); - Assert.That(d.Name, Is.EqualTo("assetAdded")); - Assert.That(d.Category, Is.EqualTo(DataItemCategory.EVENT)); - Assert.That(AssetAddedDataItem.TypeId, Is.EqualTo("ASSET_ADDED")); - Assert.That(AssetAddedDataItem.NameId, Is.EqualTo("assetAdded")); - Assert.That(AssetAddedDataItem.CategoryId, Is.EqualTo(DataItemCategory.EVENT)); - } - - // 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() - { - var d = new AssetAddedDataItem("dev01"); - Assert.That(d.Id, Is.Not.Null.And.Not.Empty); - Assert.That(d.Id, Does.Contain("dev01")); - Assert.That(d.Type, Is.EqualTo("ASSET_ADDED")); - } - - // 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() - { - var d = new AssociatedAssetIdDataItem(); - Assert.That(d.Type, Is.EqualTo(AssociatedAssetIdDataItem.TypeId)); - Assert.That(d.Name, Is.EqualTo(AssociatedAssetIdDataItem.NameId)); - Assert.That(d.Category, Is.EqualTo(AssociatedAssetIdDataItem.CategoryId)); - Assert.That(AssociatedAssetIdDataItem.TypeId, Is.EqualTo("ASSOCIATED_ASSET_ID")); - Assert.That(AssociatedAssetIdDataItem.CategoryId, Is.EqualTo(DataItemCategory.EVENT)); - } - - // 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() - { - Assert.That(typeof(AssetAddedDataItem).BaseType, Is.EqualTo(typeof(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() - { - Assert.That(typeof(AssociatedAssetIdDataItem).BaseType, Is.EqualTo(typeof(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() - { - Assert.That(AssetChangedDataItem.DescriptionText, - Is.EqualTo("AssetId of the Asset that has been changed."), - "AssetChangedDataItem description must reflect the v2.6 split " + - "where 'added' moved to AssetAddedDataItem"); - } - } -} 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 deleted file mode 100644 index 1e61a0008..000000000 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7ComponentTests.cs +++ /dev/null @@ -1,42 +0,0 @@ -using MTConnect.Devices.Components; -using NUnit.Framework; - -namespace MTConnect.NET_Common_Tests.V2_6_V2_7 -{ - // Pins the v2.7 Component subclasses (PinTool, ToolHolder). - // - // - XMI: https://github.com/mtconnect/mtconnect_sysml_model @ tag v2.7 - // UML classes under Device Information Model > Components: - // * PinTool — pin-style tooling component - // * ToolHolder — tool-holder component - // - XSD: https://schemas.mtconnect.org/schemas/MTConnectDevices_2.7.xsd - // (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() - { - var c = new PinToolComponent(); - Assert.That(c.Type, Is.EqualTo("PinTool")); - Assert.That(c.Name, Is.Null); - Assert.That(PinToolComponent.TypeId, Is.EqualTo("PinTool")); - 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() - { - var c = new ToolHolderComponent(); - Assert.That(c.Type, Is.EqualTo("ToolHolder")); - Assert.That(c.Name, Is.Null); - Assert.That(ToolHolderComponent.TypeId, Is.EqualTo("ToolHolder")); - Assert.That(ToolHolderComponent.NameId, Is.EqualTo("toolHolder")); - } - } -} 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 deleted file mode 100644 index 10503fa66..000000000 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7ConfigurationDataSetTests.cs +++ /dev/null @@ -1,175 +0,0 @@ -using MTConnect.Devices.Configurations; -using NUnit.Framework; - -namespace MTConnect.NET_Common_Tests.V2_6_V2_7 -{ - // Pins the v2.7 Configuration sub-element family: new geometric primitives - // (Axis, Origin, Rotation, Scale, Translation) and their data-set - // representation siblings (*DataSet) — plus the cross-package-grafted - // DataSet base that the universal cross-package parent resolver brought - // into the Devices.Configurations namespace. - // - // - XMI: https://github.com/mtconnect/mtconnect_sysml_model @ tag v2.7 - // UML classes under Device Information Model > Configurations: - // * Axis / AxisDataSet - // * Origin / OriginDataSet - // * Rotation / RotationDataSet - // * Scale / ScaleDataSet - // * Translation / TranslationDataSet - // plus the abstract bases (AbstractAxis, AbstractOrigin, etc.). - // - XSD: https://schemas.mtconnect.org/schemas/MTConnectDevices_2.7.xsd - // (the geometric-primitive complexTypes encode the same shape - // on the wire under ). - // - 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() - { - var ds = new DataSet(); - Assert.That(ds, Is.InstanceOf()); - Assert.That(DataSet.DescriptionText, Is.Not.Null.And.Not.Empty); - } - - // The five concrete sub-types follow the same shape: parameterless ctor, - // populates X/Y/Z (or A/B/C) fields, implements IDataSet (interface, - // 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() - { - var a = new AxisDataSet { X = 1.0, Y = 2.0, Z = 3.0 }; - Assert.That(a, Is.InstanceOf()); - Assert.That(a, Is.InstanceOf()); - Assert.That(a.X, Is.EqualTo(1.0)); - Assert.That(a.Y, Is.EqualTo(2.0)); - 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() - { - var o = new OriginDataSet { X = "1", Y = "2", Z = "3" }; - Assert.That(o, Is.InstanceOf()); - 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() - { - // Rotations are reported as A (about X), B (about Y), C (about Z). - var r = new RotationDataSet { A = "10", B = "20", C = "30" }; - Assert.That(r, Is.InstanceOf()); - 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() - { - var s = new ScaleDataSet(); - Assert.That(s, Is.InstanceOf()); - 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() - { - var t = new TranslationDataSet(); - Assert.That(t, Is.InstanceOf()); - Assert.That(t, Is.InstanceOf()); - } - - // 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() - { - var a = new Axis { Value = "X" }; - Assert.That(a, Is.InstanceOf()); - Assert.That(a, Is.InstanceOf()); - 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() - { - var o = new Origin(); - Assert.That(o, Is.InstanceOf()); - 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() - { - Assert.That(new Translation(), Is.InstanceOf()); - } - - // 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() - { - Assert.That(typeof(AbstractTranslation).IsAbstract, Is.True); - } - } -} 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 deleted file mode 100644 index 0faef2fc1..000000000 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7DataItemTypeTests.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using MTConnect.Devices; -using MTConnect.Devices.DataItems; -using NUnit.Framework; - -namespace MTConnect.NET_Common_Tests.V2_6_V2_7 -{ - // Pins every DataItem type the v2.7 SysML XMI introduces. - // - // - XMI: mtconnect/mtconnect_sysml_model @ v2.7 (SHA 25796ac591bb…) - // UML classes under Observation Information Model > Observation Types: - // * BindingState (Event) — Bonding/joining state - // * Depth (Event) — Tool / part penetration - // * FixtureAssetId (Event) — Asset reference - // * SwingAngle (Event) — Mill/lathe swing - // * SwingDiameter (Event) — Mill/lathe swing - // * SwingRadius (Event) — Mill/lathe swing - // * TaskAssetId (Event) — Asset reference - // * WaterHardness (Sample) — Coolant water mineral level - // - XSD: schemas.mtconnect.org/schemas/MTConnectStreams_2.7.xsd - // (each TypeId is encoded in the EventEnum / SampleEnum - // 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 - { - // Categories below match what the v2.7 SysML XMI declares — the spec - // 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)] - [TestCase(typeof(SwingAngleDataItem), "SWING_ANGLE", DataItemCategory.EVENT)] - [TestCase(typeof(SwingDiameterDataItem), "SWING_DIAMETER", DataItemCategory.EVENT)] - [TestCase(typeof(SwingRadiusDataItem), "SWING_RADIUS", DataItemCategory.EVENT)] - [TestCase(typeof(TaskAssetIdDataItem), "TASK_ASSET_ID", DataItemCategory.EVENT)] - [TestCase(typeof(WaterHardnessDataItem), "WATER_HARDNESS", DataItemCategory.SAMPLE)] - public void V2_7_DataItem_constructs_with_correct_metadata( - Type dataItemType, string expectedTypeId, DataItemCategory expectedCategory) - { - // Wrap with Assert.DoesNotThrow so a missing parameterless ctor - // surfaces as a clear NUnit failure with the offending type name - // rather than a bare MissingMethodException. - object? instance = null; - Assert.DoesNotThrow(() => instance = Activator.CreateInstance(dataItemType), - $"{dataItemType.Name} should have a public parameterless constructor"); - Assert.That(instance, Is.Not.Null); - Assert.That(instance, Is.InstanceOf()); - - var di = (DataItem)instance!; - Assert.That(di.Type, Is.EqualTo(expectedTypeId), - $"{dataItemType.Name}.Type should be the spec TypeId"); - Assert.That(di.Category, Is.EqualTo(expectedCategory), - $"{dataItemType.Name}.Category should be {expectedCategory}"); - - var typeIdConst = dataItemType.GetField("TypeId", - System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)?.GetRawConstantValue(); - Assert.That(typeIdConst, Is.EqualTo(expectedTypeId), - $"{dataItemType.Name}.TypeId static const should match the spec TypeId"); - } - } -} 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 deleted file mode 100644 index bc906c56b..000000000 --- a/tests/MTConnect.NET-Common-Tests/V2_6_V2_7/V2_7SampleObservationTests.cs +++ /dev/null @@ -1,66 +0,0 @@ -using MTConnect.Devices; -using MTConnect.Devices.DataItems; -using MTConnect.Observations; -using NUnit.Framework; - -namespace MTConnect.NET_Common_Tests.V2_6_V2_7 -{ - // Sample envelope coverage for the v2.7 SAMPLE-category DataItems introduced - // by [#133](https://github.com/TrakHound/MTConnect.NET/issues/133). - // - // - XMI: mtconnect/mtconnect_sysml_model @ v2.7 (SHA 25796ac591bb…) - // UML class `WaterHardnessDataItem` declares - // `category = SAMPLE`, MinimumVersion = v2.7. (Hardness measured in - // mineral content of cooling water — used in machining workflows - // where coolant chemistry affects tool life.) - // - XSD: schemas.mtconnect.org/schemas/MTConnectStreams_2.7.xsd - // enum `SampleEnum` value `WATER_HARDNESS` is the sample-category - // element name on the wire. - // - Prose: MTConnect Standard Part_2.0_Streams_v2.7 section 11 "Sample observation - // types" — describes how SAMPLE-category observations carry - // continuous-numeric values reported at agent-defined intervals. - // - // This fixture is the SAMPLE-envelope counterpart to V2_7DataItemTypeTests - // (which is shape-only). Here we focus on round-tripping a SAMPLE - // 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 - { - // Source: XMI v2.7 — `WaterHardness` is the only SAMPLE-category type - // introduced in v2.7 (the rest are EVENT). Tests the round-trip from - // creating a DataItem of this v2.7 type, attaching a SampleValueObservation, - // 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() - { - var dataItem = new WaterHardnessDataItem("dev01"); - Assert.That(dataItem.Category, Is.EqualTo(DataItemCategory.SAMPLE)); - - var observation = new SampleValueObservation - { - DataItemId = dataItem.Id, - Result = "12.5", - Timestamp = System.DateTime.UtcNow, - Sequence = 42, - }; - - // Carrier preserves DataItemId so a downstream lookup of the type - // (DataItemId → TypeId via the agent's DataItem registry) resolves - // back to WATER_HARDNESS. - Assert.That(observation.DataItemId, Is.EqualTo(dataItem.Id)); - Assert.That(observation.Result, Is.EqualTo("12.5")); - Assert.That(observation.Sequence, Is.EqualTo(42)); - - // The DataItem's Type field is what cppagent JSON / XML formatters - // look at when rendering the SAMPLE element name. - Assert.That(dataItem.Type, Is.EqualTo("WATER_HARDNESS")); - } - - } -} diff --git a/tests/MTConnect.NET-Docs-Tests/DocsReferenceGenerationTests.cs b/tests/MTConnect.NET-Docs-Tests/DocsReferenceGenerationTests.cs index 922a42391..6581091b4 100644 --- a/tests/MTConnect.NET-Docs-Tests/DocsReferenceGenerationTests.cs +++ b/tests/MTConnect.NET-Docs-Tests/DocsReferenceGenerationTests.cs @@ -124,6 +124,39 @@ public void Cli_Page_Is_In_Sync_With_Source() } } + /// + /// Direct pin for the cycle-4 DocsGen bounded-scan fix + /// (CliInventory.CollectDotNetTool): the takesValue + /// regex must be bounded to the CURRENT case block, otherwise + /// a boolean switch flag sitting above a value-taking neighbor + /// (e.g. --full-tree above case "--output": … RequireValue) + /// would falsely inherit the neighbor's <value> shape. + /// + /// + /// The golden-file Cli_Page_Is_In_Sync_With_Source test would + /// also catch this via the rendered cli.md, but a targeted + /// unit-style pin here surfaces the regression with a branch-scoped + /// failure message before the golden-file diff is even computed. + /// + /// + [Test] + public void SysMLImport_FullTree_Flag_Is_Detected_As_Switch_Not_Value_Flag() + { + var clis = CliInventory.Collect(RepoRoot); + var sysml = clis.FirstOrDefault(c => c.Name == "MTConnect.NET-SysML-Import"); + Assert.That(sysml, Is.Not.Null, + "MTConnect.NET-SysML-Import must be discovered in the inventory."); + + var fullTree = sysml!.Flags.FirstOrDefault(f => f.Name == "--full-tree"); + Assert.That(fullTree, Is.Not.Null, + "--full-tree flag must appear in the sysml-import inventory."); + Assert.That(fullTree!.ArgShape, Is.Null, + "--full-tree is a boolean switch (case body: `fullTree = true; break;`). " + + "The bounded RequireValue scan must NOT leak in the value shape from the " + + "neighboring --output / --json-dump cases. An ArgShape of `` here " + + "means the bounded-scan regex regressed to an unbounded lookahead."); + } + /// 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() diff --git a/tests/MTConnect.NET-Generator-Tests/AutoDerivePreviousXmiTests.cs b/tests/MTConnect.NET-Generator-Tests/AutoDerivePreviousXmiTests.cs new file mode 100644 index 000000000..f5d77d32e --- /dev/null +++ b/tests/MTConnect.NET-Generator-Tests/AutoDerivePreviousXmiTests.cs @@ -0,0 +1,856 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using NUnit.Framework; + +namespace MTConnect.NET_Generator_Tests +{ + /// + /// Zero-config PREV_VERSION auto-derive coverage for the SysML importer + /// (task #408 amendment to PR #233 Phase 4). + /// + /// + /// When neither --previous-xmi nor --full-tree is supplied, + /// the importer parses MTConnectVersions.Max from + /// libraries/MTConnect.NET-Common/MTConnectVersions.cs under + /// --output and resolves the prior-version XMI in this priority + /// order: + /// + /// + /// Strategy B (primary): + /// build/.cache/sysml-prev/MTConnectSysMLModel_v${PREV_VERSION}.xml. + /// + /// + /// Strategy A (fallback): + /// build/sysml-model/MTConnectSysMLModel.xml, gated on + /// git -C build/sysml-model describe --exact-match --tags HEAD + /// returning v${PREV_VERSION} exactly. + /// + /// + /// Strategy C (fail-hard): throw with an actionable message when + /// neither resolves. + /// + /// + /// + /// + /// + /// Every case here is exercised end-to-end via dotnet run --no-build + /// --project build/MTConnect.NET-SysML-Import against a synthetic + /// --output scratch tree that mimics the repo layout so the + /// auto-derive resolver sees a controlled world: a pinned + /// MTConnectVersions.cs, a curated cache directory, and (where + /// needed) a synthetic git-tagged build/sysml-model. The + /// assertions bind to the CLI contract, not to any internal helper. + /// + /// + [TestFixture] + public class AutoDerivePreviousXmiTests + { + private const string SlnFileName = "MTConnect.NET.sln"; + private const string GeneratorProject = "build/MTConnect.NET-SysML-Import"; + private const string RealXmiRelativePath = "build/sysml-model/MTConnectSysMLModel.xml"; + private const string ScratchRoot = ".claude/gen-test-out/auto-derive"; + + // A minimal MTConnectVersions.cs skeleton — enough for the auto-derive + // regex to lock onto `public static Version Max => VersionXY;` and + // `public static readonly Version VersionXY = new Version(X, Y);`. The + // constants below cover the Max we pin the tests against; the + // `Version27` constant matches the current-tree Max at #233 landing + // so the tests stay in step with the shipped fixture XMI. + private const string SyntheticVersionsCs = @"// Copyright (c) 2026 TrakHound Inc. + +using System; + +namespace MTConnect +{ + public static class MTConnectVersions + { + public static Version Max => Version27; + + public static readonly Version Version26 = new Version(2, 6); + public static readonly Version Version27 = new Version(2, 7); + } +} +"; + + [Test] + public void Auto_derive_from_MTConnectVersionsMax_uses_cache_when_present() + { + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + Assert.That(File.Exists(realXmi), Is.True, + $"XMI snapshot missing at {realXmi}. Is the build/sysml-model submodule initialized?"); + + var scratch = InitScratchRepoLayout("cache-primary"); + WriteSyntheticVersionsCs(scratch); + + // Strategy B setup: populate the cache path with the current-tree + // XMI as a stand-in for the prior-version XMI. Using the same bytes + // for --new-xmi and the cache produces a "same XMI on both sides" + // delta — every emitted file lands in the UNCHANGED-concentrated + // partition, so the stdout stats line is grep-able for + // `unchanged-concentrated=N>0` and the Compat file appears at the + // expected auto-derived label path. + var cacheDir = Path.Combine(scratch, "build", ".cache", "sysml-prev"); + Directory.CreateDirectory(cacheDir); + var cachePath = Path.Combine(cacheDir, "MTConnectSysMLModel_v2.7.xml"); + File.Copy(realXmi, cachePath); + + var (exitCode, stdout, stderr) = RunAutoDerive(realXmi, scratch); + + Assert.That(exitCode, Is.Zero, + $"Auto-derive with cache present should succeed.\nstdout:\n{stdout}\nstderr:\n{stderr}"); + Assert.That(stdout, Does.Contain("auto-derived from MTConnectVersions.Max"), + "stdout must announce that PREV_VERSION was auto-derived so the operator sees which strategy fired."); + Assert.That(stdout, Does.Contain("MTConnectSysMLModel_v2.7.xml"), + "stdout must echo the resolved cache path so the operator can verify Strategy B ran."); + Assert.That(stdout, Does.Contain("Delta emission:"), + "Auto-derive must reach the delta emitter, not the full-tree branch."); + + // The auto-derived Compat label is `v2_7` (from Max = Version27), + // and same-XMI-on-both-sides forces every file into the UNCHANGED + // partition — so exactly one Compat/v2_7.g.cs lands per library. + var compatFiles = Directory + .EnumerateFiles(scratch, "v2_7.g.cs", SearchOption.AllDirectories) + .Select(p => p.Replace('\\', '/')) + .Where(p => p.Contains("/Compat/")) + .ToList(); + Assert.That(compatFiles.Count, Is.EqualTo(3), + "One auto-labeled Compat file per library (three libraries): " + + string.Join(", ", compatFiles)); + } + + [Test] + public void Auto_derive_from_MTConnectVersionsMax_falls_back_to_submodule_tag_when_cache_absent() + { + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + Assert.That(File.Exists(realXmi), Is.True, + $"XMI snapshot missing at {realXmi}. Is the build/sysml-model submodule initialized?"); + + var scratch = InitScratchRepoLayout("submodule-fallback"); + WriteSyntheticVersionsCs(scratch); + // No cache path populated — Strategy B misses. Strategy A must fire. + + // Strategy A setup: build a synthetic git repo at + // /build/sysml-model, drop the XMI in, and tag HEAD as + // v2.7 (matching MTConnectVersions.Max in the synthetic + // MTConnectVersions.cs). The auto-derive resolver runs + // `git -C build/sysml-model describe --exact-match --tags HEAD` + // and accepts the tree only when the tag matches exactly. + var submoduleDir = Path.Combine(scratch, "build", "sysml-model"); + Directory.CreateDirectory(submoduleDir); + File.Copy(realXmi, Path.Combine(submoduleDir, "MTConnectSysMLModel.xml")); + InitGitRepoWithTag(submoduleDir, "v2.7"); + + var (exitCode, stdout, stderr) = RunAutoDerive(realXmi, scratch); + + Assert.That(exitCode, Is.Zero, + $"Auto-derive with only the submodule-tag path available should succeed.\n" + + $"stdout:\n{stdout}\nstderr:\n{stderr}"); + Assert.That(stdout, Does.Contain("auto-derived from MTConnectVersions.Max"), + "stdout must announce the auto-derive."); + Assert.That(stdout, Does.Contain(Path.Combine(submoduleDir, "MTConnectSysMLModel.xml")), + "stdout must echo the resolved submodule XMI path so the operator can verify Strategy A ran."); + Assert.That(stdout, Does.Contain("Delta emission:"), + "Strategy A must reach the delta emitter, not the full-tree branch."); + } + + [Test] + public void Auto_derive_from_MTConnectVersionsMax_fails_hard_when_neither_cache_nor_tag_resolves() + { + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("fail-hard"); + WriteSyntheticVersionsCs(scratch); + // No cache populated. No submodule directory populated. + + var (exitCode, _, stderr) = RunAutoDerive(realXmi, scratch); + + Assert.That(exitCode, Is.Not.Zero, + "Neither Strategy B nor Strategy A resolving must fail the invocation, not silently no-op."); + Assert.That(stderr, Does.Contain("PREV_VERSION auto-derivation"), + "stderr must name the auto-derive failure class so the operator knows which resolver aborted."); + Assert.That(stderr, Does.Contain("MTConnectVersions.Max = 2.7"), + "stderr must state the resolved PREV_VERSION so the operator can cross-check the current Max."); + Assert.That(stderr, Does.Contain("MTConnectSysMLModel_v2.7.xml"), + "stderr must name the probed cache path so the operator can drop the file in."); + Assert.That(stderr, Does.Contain("v2.7"), + "stderr must name the expected submodule tag so the operator can check the submodule tip."); + Assert.That(stderr, Does.Contain("--previous-xmi"), + "stderr must direct the operator to the explicit-override flag."); + Assert.That(stderr, Does.Contain("--full-tree"), + "stderr must direct the operator to the delta-disable escape hatch."); + } + + [Test] + public void Auto_derived_label_carries_the_auto_derived_suffix_on_stdout() + { + // Label-lie guard positive branch (F-IMP cycle 4): when the + // Compat label is genuinely auto-derived (no explicit + // --compat-version-label passed, zero-config prev-XMI resolved), + // the stdout `Label:` line must carry the "(auto-derived)" + // suffix so the operator sees at a glance which resolution + // strategy the CLI took. The `compatLabelIsAutoDerived` bool + // in Program.cs is TRUE on this branch. + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("label-auto-derived-suffix"); + WriteSyntheticVersionsCs(scratch); + var cacheDir = Path.Combine(scratch, "build", ".cache", "sysml-prev"); + Directory.CreateDirectory(cacheDir); + File.Copy(realXmi, Path.Combine(cacheDir, "MTConnectSysMLModel_v2.7.xml")); + + var (exitCode, stdout, stderr) = RunAutoDerive(realXmi, scratch); + Assert.That(exitCode, Is.Zero, $"stdout:\n{stdout}\nstderr:\n{stderr}"); + Assert.That(stdout, Does.Contain("Label: v2_7 (auto-derived)"), + "Auto-derived label must be announced with the \"(auto-derived)\" suffix — " + + "positive branch of the compatLabelIsAutoDerived ternary in Program.cs."); + } + + [Test] + public void Explicit_label_alongside_zero_config_prev_xmi_does_not_get_auto_derived_suffix() + { + // Label-lie guard negative branch (F-IMP cycle 4): the + // operator can pass an explicit --compat-version-label + // ALONGSIDE the zero-config prev-XMI path. The explicit label + // wins the `??=` default; annotating it "(auto-derived)" + // would be a lie. Pre-fix, the stdout unconditionally + // suffixed "(auto-derived)" whenever the delta mode + // announcement fired without --previous-xmi; the fix + // introduced a `compatLabelIsAutoDerived` bool so only the + // genuinely auto-derived branch appends the suffix. + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("label-explicit-no-suffix"); + WriteSyntheticVersionsCs(scratch); + var cacheDir = Path.Combine(scratch, "build", ".cache", "sysml-prev"); + Directory.CreateDirectory(cacheDir); + File.Copy(realXmi, Path.Combine(cacheDir, "MTConnectSysMLModel_v2.7.xml")); + + const string explicitLabel = "Custom-Release-Label"; + var (exitCode, stdout, stderr) = RunGenerator(scratch, + "--new-xmi", realXmi, + "--output", scratch, + "--compat-version-label", explicitLabel); + + Assert.That(exitCode, Is.Zero, $"stdout:\n{stdout}\nstderr:\n{stderr}"); + Assert.That(stdout, Does.Contain($"Label: {explicitLabel}"), + "The explicit --compat-version-label must appear on the Label: line."); + Assert.That(stdout, Does.Not.Contain($"Label: {explicitLabel} (auto-derived)"), + "The explicit label must NOT carry the \"(auto-derived)\" suffix — the " + + "operator supplied it themselves, so the suffix would misattribute " + + "authorship. This is the negative branch of the compatLabelIsAutoDerived " + + "ternary and the direct pin for the cycle-4 label-lie fix."); + Assert.That(stdout, Does.Contain("Mode: delta (zero-config)"), + "The zero-config delta path must still fire — the auto-derive resolver " + + "runs (the cache is resolved), only the label default is bypassed."); + } + + [Test] + public void Explicit_previous_xmi_wins_over_auto_derive() + { + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("explicit-wins"); + WriteSyntheticVersionsCs(scratch); + + // Populate the cache with a MUTATED copy of the XMI. If the + // resolver picked the cache (Strategy B) over the explicit + // --previous-xmi, the delta would surface CoordinateSystem-shaped + // changes (from the mutation) instead of zero-change output. The + // explicit --previous-xmi points at the pristine XMI, matching + // --new-xmi bit-for-bit, so a correctly-prioritized resolver + // produces `changed=0` while a broken one produces `changed>0`. + var cacheDir = Path.Combine(scratch, "build", ".cache", "sysml-prev"); + Directory.CreateDirectory(cacheDir); + var cachePath = Path.Combine(cacheDir, "MTConnectSysMLModel_v2.7.xml"); + var mutated = File.ReadAllText(realXmi) + .Replace( + "unchangeable coordinate system that has machine zero as its origin.", + "OVERRIDE_TEST_MARKER coordinate system that has machine zero as its origin."); + File.WriteAllText(cachePath, mutated); + + var (exitCode, stdout, stderr) = RunWithExplicitPrevious(realXmi, previousXmi: realXmi, scratch); + + Assert.That(exitCode, Is.Zero, + $"Explicit --previous-xmi should succeed even when the cache carries a different XMI.\n" + + $"stdout:\n{stdout}\nstderr:\n{stderr}"); + Assert.That(stdout, Does.Not.Contain("auto-derived from MTConnectVersions.Max"), + "Explicit --previous-xmi must skip the auto-derive announcement — the delta is operator-directed."); + Assert.That(stdout, Does.Contain("--previous-xmi override"), + "stdout must announce the explicit-override mode so the operator sees which path fired."); + + // If the resolver had picked the cache, the mutation would surface + // as CHANGED files. With the explicit prev matching the new XMI, + // changed=0. + var stats = ParseChanged(stdout); + Assert.That(stats, Is.Zero, + "Explicit --previous-xmi matched --new-xmi bit-for-bit; changed must be zero. " + + "A non-zero count means the cache leaked into the delta — the explicit override lost."); + } + + [Test] + public void Missing_MTConnectVersions_cs_fails_with_actionable_message() + { + // ReadMTConnectVersionsMax throws FileNotFoundException when the + // versions file is absent under --output. The top-level try/catch + // in Program.cs (lines 172-182) maps that to stderr `error: ...` + // + exit 1. Pin the actionable message the operator sees so a + // later refactor of the error text still names all four + // recovery paths (probed file path, --previous-xmi override, + // --full-tree escape hatch, expected file location). + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("versions-cs-missing"); + // Deliberately do NOT write MTConnectVersions.cs — the guard + // must fire before the resolver reaches Strategy A/B/C. + + var (exitCode, _, stderr) = RunAutoDerive(realXmi, scratch); + + Assert.That(exitCode, Is.EqualTo(1), + $"Missing MTConnectVersions.cs must exit 1 via the top-level catch, not stack-trace.\nstderr:\n{stderr}"); + Assert.That(stderr, Does.Contain("MTConnectVersions.cs not found"), + "stderr must name the missing file so the operator can locate it."); + Assert.That(stderr, Does.Contain("--previous-xmi"), + "stderr must direct the operator to the explicit-override flag."); + Assert.That(stderr, Does.Contain("--full-tree"), + "stderr must direct the operator to the delta-disable escape hatch."); + } + + [Test] + public void MTConnectVersions_cs_without_Max_declaration_fails_hard() + { + // The Max regex miss surfaces as InvalidOperationException → + // top-level catch → exit 1 with a message that pinpoints the + // convention the parser expects. Write a syntactically-valid + // C# file that carries no `public static Version Max => ...` + // property so the regex miss fires; the parser must reject + // rather than silently no-op or default to a wrong version. + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("versions-cs-no-max"); + var targetPath = Path.Combine( + scratch, "libraries", "MTConnect.NET-Common", "MTConnectVersions.cs"); + File.WriteAllText(targetPath, @"// Missing Max property; the parser must reject this file. +using System; +namespace MTConnect +{ + public static class MTConnectVersions + { + public static readonly Version Version27 = new Version(2, 7); + } +} +"); + + var (exitCode, _, stderr) = RunAutoDerive(realXmi, scratch); + + Assert.That(exitCode, Is.EqualTo(1), + $"Missing Max property must exit 1 via the top-level catch.\nstderr:\n{stderr}"); + Assert.That(stderr, Does.Contain("Could not locate"), + "stderr must announce a parse-shape failure, not a resolver failure."); + Assert.That(stderr, Does.Contain("Max"), + "stderr must name the missing convention element so the operator knows what to restore."); + Assert.That(stderr, Does.Contain("--previous-xmi"), + "stderr must direct the operator to the explicit-override flag."); + } + + [Test] + public void MTConnectVersions_cs_without_const_table_entry_fails_hard() + { + // The Max property resolves to a VersionXY constant that must + // exist in the file's const table. If Max => VersionNN but no + // `public static readonly Version VersionNN = new Version(...)`, + // the resolver throws InvalidOperationException. This exercises + // the second `if (!constMatch.Success)` branch, distinct from + // the Max-regex-miss branch above. + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("versions-cs-no-const"); + var targetPath = Path.Combine( + scratch, "libraries", "MTConnect.NET-Common", "MTConnectVersions.cs"); + File.WriteAllText(targetPath, @"// Max points at Version99 which is not declared. +using System; +namespace MTConnect +{ + public static class MTConnectVersions + { + public static Version Max => Version99; + public static readonly Version Version27 = new Version(2, 7); + } +} +"); + + var (exitCode, _, stderr) = RunAutoDerive(realXmi, scratch); + + Assert.That(exitCode, Is.EqualTo(1), + $"Missing const-table entry must exit 1 via the top-level catch.\nstderr:\n{stderr}"); + Assert.That(stderr, Does.Contain("Version99"), + "stderr must name the un-resolvable constant so the operator can add it."); + Assert.That(stderr, Does.Contain("Could not locate"), + "stderr must carry the parse-shape failure fingerprint."); + } + + [Test] + public void Commented_out_Max_declaration_does_not_confuse_the_parser() + { + // Regression pin (F-IMP-401, dime cycle 3): a stale + // `// public static Version Max => Version27;` line commented out + // above the LIVE `public static Version Max => Version29;` line + // would win the first-match regex without a comment-strip pass, + // pinning PREV_VERSION to the wrong version (v2.7 not v2.9). This + // fixture writes such a file with an OLD version commented out + // above a NEW version live, then populates the cache path for the + // NEW version. Auto-derive must pick up the NEW version (v2.9), + // resolving the NEW cache path and NOT the OLD one. + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("commented-max-decoy"); + + // MTConnectVersions.cs with a commented-out decoy Max line above + // the live Max line. Both line comments (`//`) and a block-comment + // (`/* ... */`) decoy are exercised so the strip covers both + // shapes. + var versionsPath = Path.Combine( + scratch, "libraries", "MTConnect.NET-Common", "MTConnectVersions.cs"); + File.WriteAllText(versionsPath, @"// Copyright (c) 2026 TrakHound Inc. + +using System; + +namespace MTConnect +{ + public static class MTConnectVersions + { + // Historical decoy — the pre-bump Max line, kept as documentation. + // public static Version Max => Version27; + + /* Alternative shape decoy retained for reference: + public static Version Max => Version28; + */ + + public static Version Max => Version29; + + public static readonly Version Version27 = new Version(2, 7); + public static readonly Version Version28 = new Version(2, 8); + public static readonly Version Version29 = new Version(2, 9); + } +} +"); + + // Populate the cache for v2.9 ONLY. If the parser is fooled by + // either comment-out decoy, it will look for v2.7 or v2.8 cache + // paths (which are absent), fall through to Strategy C, and + // fail-hard with a version-mismatched fingerprint. + var cacheDir = Path.Combine(scratch, "build", ".cache", "sysml-prev"); + Directory.CreateDirectory(cacheDir); + File.Copy(realXmi, Path.Combine(cacheDir, "MTConnectSysMLModel_v2.9.xml")); + + var (exitCode, stdout, stderr) = RunAutoDerive(realXmi, scratch); + + Assert.That(exitCode, Is.Zero, + $"Comment-stripped parse must pick the live Max = Version29 and hit the v2.9 cache.\n" + + $"stdout:\n{stdout}\nstderr:\n{stderr}"); + Assert.That(stdout, Does.Contain("MTConnectSysMLModel_v2.9.xml"), + "The comment-stripped parse must resolve the v2.9 cache path (live Max), " + + "not the v2.7 / v2.8 decoy paths."); + Assert.That(stdout, Does.Not.Contain("MTConnectSysMLModel_v2.7.xml"), + "The commented-out `Max => Version27` decoy must not fool the parser."); + Assert.That(stdout, Does.Not.Contain("MTConnectSysMLModel_v2.8.xml"), + "The block-commented `Max => Version28` decoy must not fool the parser."); + } + + [Test] + public void Prev_equals_new_warns_and_no_ops_when_new_xmi_filename_encodes_current_max() + { + // PREV == NEW guard: when the new XMI's filename encodes the same + // version as the auto-derived PREV_VERSION (from MTConnectVersions.Max), + // the delta is empty by construction — the max already matches the + // version being generated. Exit 0 + a warning on stderr, no delta + // emit. Filename convention is `MTConnectSysMLModel_v..xml`. + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + Assert.That(File.Exists(realXmi), Is.True, + $"XMI snapshot missing at {realXmi}. Is the build/sysml-model submodule initialized?"); + + var scratch = InitScratchRepoLayout("prev-eq-new-guard"); + WriteSyntheticVersionsCs(scratch); + + // Populate the cache so Strategy B resolves — the guard runs AFTER + // ResolvePreviousXmi succeeds. Without a cache, Strategy C would + // fire and exit 1 before the guard could evaluate. + var cacheDir = Path.Combine(scratch, "build", ".cache", "sysml-prev"); + Directory.CreateDirectory(cacheDir); + File.Copy(realXmi, Path.Combine(cacheDir, "MTConnectSysMLModel_v2.7.xml")); + + // Copy realXmi to a filename that matches MTConnectVersions.Max (v2.7) + // so the guard's filename regex matches and the versions equate. + var newXmiVersioned = Path.Combine(scratch, "MTConnectSysMLModel_v2.7.xml"); + File.Copy(realXmi, newXmiVersioned); + + var (exitCode, stdout, stderr) = RunAutoDerive(newXmiVersioned, scratch); + + Assert.That(exitCode, Is.Zero, + $"PREV==NEW must exit 0 with warning, not fail.\nstdout:\n{stdout}\nstderr:\n{stderr}"); + Assert.That(stderr, Does.Contain("already supported by MTConnectVersions.Max"), + "stderr must announce the no-delta-to-derive warning so the operator sees why nothing was emitted."); + Assert.That(stderr, Does.Contain("v2.7"), + "stderr must name the version so the operator can verify the guard fired on the intended version."); + Assert.That(stdout, Does.Not.Contain("Delta emission:"), + "PREV==NEW must skip the delta emitter — no-op semantics."); + } + + [Test] + public void Prev_equals_new_guard_stays_silent_when_new_xmi_filename_has_no_version_suffix() + { + // The PREV==NEW guard predicates on the new XMI filename encoding a + // version via the `_v..xml` suffix. A filename without + // that suffix (the default `MTConnectSysMLModel.xml` snapshot shape) + // must fall through to the normal delta emit — no warning, no early + // return, even when MTConnectVersions.Max would numerically match + // the underlying XMI's version. This preserves the default Phase 3 + // workflow where the newXmi is the un-suffixed submodule snapshot. + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("prev-eq-new-unsuffixed"); + WriteSyntheticVersionsCs(scratch); + + var cacheDir = Path.Combine(scratch, "build", ".cache", "sysml-prev"); + Directory.CreateDirectory(cacheDir); + File.Copy(realXmi, Path.Combine(cacheDir, "MTConnectSysMLModel_v2.7.xml")); + + // newXmi is realXmi at its default un-suffixed path — guard's regex + // does not match, guard stays silent, delta emitter runs. + var (exitCode, stdout, stderr) = RunAutoDerive(realXmi, scratch); + + Assert.That(exitCode, Is.Zero, + $"Un-suffixed new-xmi filename must NOT trigger the guard.\nstdout:\n{stdout}\nstderr:\n{stderr}"); + Assert.That(stderr, Does.Not.Contain("already supported by MTConnectVersions.Max"), + "Un-suffixed filename must not trigger the PREV==NEW warning."); + Assert.That(stdout, Does.Contain("Delta emission:"), + "Un-suffixed filename must reach the delta emitter, not the guard's early return."); + } + + [Test] + public void Submodule_dir_without_git_repo_falls_through_to_fail_hard() + { + // Strategy A gates on TryGetSubmoduleTag returning a matching + // tag. When the submodule dir exists and holds an XMI but is + // NOT a git repository, `git describe` fails and + // TryGetSubmoduleTag returns null — Strategy A rejects, and + // Strategy C fires. Distinct from the "no submodule dir at all" + // path already covered by the fail-hard fixture. + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("submodule-not-git"); + WriteSyntheticVersionsCs(scratch); + + var submoduleDir = Path.Combine(scratch, "build", "sysml-model"); + Directory.CreateDirectory(submoduleDir); + File.Copy(realXmi, Path.Combine(submoduleDir, "MTConnectSysMLModel.xml")); + // NO git init — TryGetSubmoduleTag must return null. + + var (exitCode, _, stderr) = RunAutoDerive(realXmi, scratch); + + Assert.That(exitCode, Is.EqualTo(1), + $"A non-git submodule dir must fall through to Strategy C, not Strategy A.\nstderr:\n{stderr}"); + Assert.That(stderr, Does.Contain("PREV_VERSION auto-derivation"), + "stderr must announce the Strategy-C fail-hard, not accept the un-tagged tree."); + Assert.That(stderr, Does.Contain("v2.7"), + "stderr must state the expected submodule tag so the operator sees which tag was required."); + } + + [Test] + public void Submodule_git_repo_with_wrong_tag_falls_through_to_fail_hard() + { + // Strategy A accepts only an EXACT-match tag. A git repo tagged + // v9.9 (not v2.7 = MTConnectVersions.Max) must reject and fall + // through to Strategy C. This exercises the branch where + // TryGetSubmoduleTag returns a non-null string that fails the + // Ordinal comparison against expectedTag. + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("submodule-wrong-tag"); + WriteSyntheticVersionsCs(scratch); + + var submoduleDir = Path.Combine(scratch, "build", "sysml-model"); + Directory.CreateDirectory(submoduleDir); + File.Copy(realXmi, Path.Combine(submoduleDir, "MTConnectSysMLModel.xml")); + InitGitRepoWithTag(submoduleDir, "v9.9"); + + var (exitCode, _, stderr) = RunAutoDerive(realXmi, scratch); + + Assert.That(exitCode, Is.EqualTo(1), + $"A wrong-tagged submodule must fall through to Strategy C.\nstderr:\n{stderr}"); + Assert.That(stderr, Does.Contain("PREV_VERSION auto-derivation"), + "stderr must announce the Strategy-C fail-hard, not silently accept the wrong tag."); + Assert.That(stderr, Does.Contain("v2.7"), + "stderr must state the expected tag (v2.7) so the operator sees the mismatch."); + } + + [Test] + public void Full_tree_flag_disables_delta_mode() + { + var repoRoot = FindRepoRoot(); + var realXmi = Path.Combine(repoRoot, RealXmiRelativePath); + + var scratch = InitScratchRepoLayout("full-tree"); + WriteSyntheticVersionsCs(scratch); + + // Populate the cache so auto-derive WOULD succeed if it were + // allowed to run. --full-tree must skip both delta paths and + // trigger the full-tree branch instead, producing no Compat + // file and no `Delta emission:` stats line. + var cacheDir = Path.Combine(scratch, "build", ".cache", "sysml-prev"); + Directory.CreateDirectory(cacheDir); + File.Copy(realXmi, Path.Combine(cacheDir, "MTConnectSysMLModel_v2.7.xml")); + + var (exitCode, stdout, stderr) = RunWithFullTree(realXmi, scratch); + + Assert.That(exitCode, Is.Zero, + $"--full-tree must succeed against a valid tree.\nstdout:\n{stdout}\nstderr:\n{stderr}"); + Assert.That(stdout, Does.Contain("full-tree"), + "stdout must announce that the full-tree path fired."); + Assert.That(stdout, Does.Not.Contain("Delta emission:"), + "--full-tree must skip the delta emitter's stats line — the delta path is fully disabled."); + Assert.That(stdout, Does.Not.Contain("auto-derived from MTConnectVersions.Max"), + "--full-tree must short-circuit before the auto-derive resolver runs."); + + var compatFiles = Directory + .EnumerateFiles(scratch, "*.g.cs", SearchOption.AllDirectories) + .Where(p => p.Replace('\\', '/').Contains("/Compat/")) + .ToList(); + Assert.That(compatFiles, Is.Empty, + "--full-tree must emit zero Compat/*.g.cs files (Compat is delta-mode-only). " + + "Unexpected Compat files:\n " + string.Join("\n ", compatFiles)); + + // Full-tree emits the whole tree — at least the current-XMI + // baseline count of files. The committed tree ships ~892 .g.cs + // files at v2.7 landing (2026-08-20); pin a floor of 700 so + // ordinary spec-shrink drift (a version dropping ~15 types) is + // tolerated but a delta-mode leakage (which would emit only the + // ~10-file diff, not the full tree) trips the guard loudly. + // A previous `>100` threshold accepted any partial emission + // including the delta subset. + var emittedFiles = Directory + .EnumerateFiles(scratch, "*.g.cs", SearchOption.AllDirectories) + .Count(); + Assert.That(emittedFiles, Is.GreaterThan(700), + "--full-tree must emit the whole generated tree, not the delta subset. " + + $"Actual .g.cs count: {emittedFiles}. A count in the ~10-100 range " + + "signals a delta-mode leak; a count under 700 signals substantial spec " + + "shrink and should ratchet this floor after human review."); + } + + // --- helpers ----------------------------------------------------- + + private static string FindRepoRoot() + { + var current = new DirectoryInfo(AppContext.BaseDirectory); + while (current != null) + { + if (File.Exists(Path.Combine(current.FullName, SlnFileName))) + return current.FullName; + current = current.Parent; + } + throw new DirectoryNotFoundException( + $"Could not locate {SlnFileName} in any ancestor of {AppContext.BaseDirectory}."); + } + + // Creates the scratch dir with a repo-like layout: the three library + // subdirectories the renderers guard against, plus the build/ tree + // ancestor that the cache and submodule strategies probe under. + private static string InitScratchRepoLayout(string suffix) + { + var repoRoot = FindRepoRoot(); + var path = Path.Combine(repoRoot, ScratchRoot, suffix); + if (Directory.Exists(path)) + { + // A prior test run may have left a synthetic git repo behind + // whose .git/objects tree resists a plain recursive delete on + // some filesystems. Two-pass delete: first try recursive, + // then if that fails, chmod the tree writable and retry. + TryDeleteTree(path); + } + Directory.CreateDirectory(path); + Directory.CreateDirectory(Path.Combine(path, "libraries", "MTConnect.NET-Common")); + Directory.CreateDirectory(Path.Combine(path, "libraries", "MTConnect.NET-JSON-cppagent")); + Directory.CreateDirectory(Path.Combine(path, "libraries", "MTConnect.NET-XML")); + Directory.CreateDirectory(Path.Combine(path, "build")); + return path; + } + + private static void TryDeleteTree(string path) + { + try + { + Directory.Delete(path, recursive: true); + } + catch (UnauthorizedAccessException) + { + // Loose read-only bits on git pack files trip the plain delete + // on Windows; clear them and retry once. + foreach (var f in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)) + { + try { File.SetAttributes(f, FileAttributes.Normal); } catch { } + } + Directory.Delete(path, recursive: true); + } + } + + private static void WriteSyntheticVersionsCs(string scratch) + { + var target = Path.Combine( + scratch, "libraries", "MTConnect.NET-Common", "MTConnectVersions.cs"); + File.WriteAllText(target, SyntheticVersionsCs); + } + + // Bootstraps a minimal git repo at `dir`, stages every present file, + // commits, and tags the commit `tagName`. The auto-derive Strategy A + // path runs `git -C describe --exact-match --tags HEAD`; this + // helper produces the shape that lookup expects. + // + // Every git config that could pull in a signing hook is disabled + // per-repo (commit.gpgsign, tag.gpgsign, tag.forceSignAnnotated) so the + // helper works on a developer host with the tester's global-config + // signing hooks (ottobolyos runs `commit.gpgsign=true` + `tag.gpgsign=true` + // globally — those defaults would abort the synthetic tag on a host + // without a matching GPG key context). + private static void InitGitRepoWithTag(string dir, string tagName) + { + RunGit(dir, "init", "-q"); + RunGit(dir, "config", "user.email", "auto-derive-test@example.invalid"); + RunGit(dir, "config", "user.name", "Auto Derive Test"); + RunGit(dir, "config", "commit.gpgsign", "false"); + RunGit(dir, "config", "tag.gpgsign", "false"); + RunGit(dir, "config", "tag.forceSignAnnotated", "false"); + RunGit(dir, "add", "-A"); + RunGit(dir, "commit", "-q", "-m", "synthetic sysml-model snapshot for auto-derive test"); + // Explicit lightweight tag — no `-a`, no `-s`, no message — so the + // synthetic tag lands regardless of tester-side GPG state. The + // per-repo `tag.gpgsign=false` above is defense-in-depth for the + // same concern. + RunGit(dir, "tag", tagName); + } + + private static void RunGit(string workingDir, params string[] args) + { + var psi = new ProcessStartInfo("git") + { + WorkingDirectory = workingDir, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + foreach (var a in args) + psi.ArgumentList.Add(a); + + using var proc = Process.Start(psi) + ?? throw new InvalidOperationException($"Failed to start git {string.Join(' ', args)}."); + var stdoutTask = proc.StandardOutput.ReadToEndAsync(); + var stderrTask = proc.StandardError.ReadToEndAsync(); + System.Threading.Tasks.Task.WhenAll(stdoutTask, stderrTask).GetAwaiter().GetResult(); + proc.WaitForExit(); + if (proc.ExitCode != 0) + { + throw new InvalidOperationException( + $"git {string.Join(' ', args)} exited {proc.ExitCode} in {workingDir}. " + + $"stderr:\n{stderrTask.Result}"); + } + } + + // Auto-derive invocation shape: only --new-xmi + --output. No + // --previous-xmi, no --full-tree — this is exactly the zero-config + // form Phase 3 of the version-bump plan calls. + private static (int ExitCode, string Stdout, string Stderr) RunAutoDerive( + string newXmi, string output) + { + return RunGenerator(output, "--new-xmi", newXmi, "--output", output); + } + + private static (int ExitCode, string Stdout, string Stderr) RunWithExplicitPrevious( + string newXmi, string previousXmi, string output) + { + return RunGenerator(output, + "--new-xmi", newXmi, + "--previous-xmi", previousXmi, + "--output", output); + } + + private static (int ExitCode, string Stdout, string Stderr) RunWithFullTree( + string newXmi, string output) + { + return RunGenerator(output, + "--new-xmi", newXmi, + "--output", output, + "--full-tree"); + } + + private static (int ExitCode, string Stdout, string Stderr) RunGenerator( + string outputRootForCwd, params string[] cliArgs) + { + var repoRoot = FindRepoRoot(); + var psi = new ProcessStartInfo("dotnet") + { + // Run `dotnet run` from the REAL repo root so the generator + // project builds correctly (the ProjectReference on the test + // csproj already built it, and --no-build below reuses that + // output). The generator's --output points at the SCRATCH + // dir, so all path probes land there. + WorkingDirectory = repoRoot, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + psi.ArgumentList.Add("run"); + psi.ArgumentList.Add("--no-build"); + psi.ArgumentList.Add("--project"); + psi.ArgumentList.Add(GeneratorProject); + psi.ArgumentList.Add("--"); + foreach (var arg in cliArgs) + psi.ArgumentList.Add(arg); + + using var proc = Process.Start(psi) + ?? throw new InvalidOperationException("Failed to start dotnet run for the generator."); + + // Drain stdout and stderr concurrently — see ByteIdenticalRegenTests + // for the deadlock defense this pattern encodes. + var stdoutTask = proc.StandardOutput.ReadToEndAsync(); + var stderrTask = proc.StandardError.ReadToEndAsync(); + System.Threading.Tasks.Task.WhenAll(stdoutTask, stderrTask).GetAwaiter().GetResult(); + proc.WaitForExit(); + return (proc.ExitCode, stdoutTask.Result, stderrTask.Result); + } + + // Extracts the `changed=N` value from the delta stats line so the + // explicit-override test can pin the CHANGED count. Returns -1 on + // absent stats line (which is a distinct failure mode from + // changed=0). + private static int ParseChanged(string stdout) + { + var match = System.Text.RegularExpressions.Regex.Match( + stdout, @"Delta emission:.*?changed=(?\d+)"); + if (!match.Success) + throw new AssertionException( + "stdout does not carry the expected 'Delta emission: ... changed=N ...' stats line.\n" + + stdout); + return int.Parse(match.Groups["c"].Value); + } + } +} diff --git a/tests/MTConnect.NET-Generator-Tests/ByteIdenticalRegenTests.cs b/tests/MTConnect.NET-Generator-Tests/ByteIdenticalRegenTests.cs new file mode 100644 index 000000000..adcdc5bb3 --- /dev/null +++ b/tests/MTConnect.NET-Generator-Tests/ByteIdenticalRegenTests.cs @@ -0,0 +1,262 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using NUnit.Framework; + +namespace MTConnect.NET_Generator_Tests +{ + /// + /// Byte-identical regeneration guards for the SysML importer. + /// + /// Two guards land side by side: + /// + /// + /// — + /// the everyday guard. Regenerates the tree twice against the same + /// XMI and asserts the two emitted trees are byte-identical. This + /// locks in the determinism guarantee the template consolidations + /// in Phase 3 rely on: any consolidation that alters emission + /// behavior flips this test RED regardless of whether the + /// committed libraries/**/*.g.cs tree is currently in sync + /// with the generator. + /// — + /// the strict baseline guard. Diffs a fresh regen against the + /// committed tree and fails on any drift. The Phase 3.1 dry-run + /// on 2026-08-20 surfaced a 78-file drift (15 committed + /// .g.cs files the generator no longer emits + 63 files + /// with content drift); Phase 4.1 resolved every case in the + /// preceding commit train (10 missing Pallet measurement + /// interfaces routed through a new template + MeasurementModel + /// .RenderInterface() wire-up, 5 orphaned .g.cs files + /// deleted after a codebase-wide grep confirmed zero consumers, + /// 63 whitespace-drift files refreshed to current-generator + /// output). The guard now runs on every CI test sweep. + /// + /// + /// Scope decision (ottobolyos 2026-08-20): current-XMI only. The + /// build/sysml-model submodule ships one snapshot per MTConnect + /// Standard version bump; iterating over historical XMI tags is not part + /// of the Phase 3 scope. When a new spec version lands, a sibling + /// byte-identical guard commit adds coverage for that version's XMI. + /// + [TestFixture] + public class ByteIdenticalRegenTests + { + // Well-known repo-relative paths. Discovery walks up from the test + // assembly's base directory to the repo root (the first ancestor + // that contains MTConnect.NET.sln). + private const string SlnFileName = "MTConnect.NET.sln"; + private const string GeneratorProject = "build/MTConnect.NET-SysML-Import"; + private const string XmiRelativePath = "build/sysml-model/MTConnectSysMLModel.xml"; + private const string GenScratchDirPrimary = ".claude/gen-test-out/byte-identical"; + private const string GenScratchDirSecondary = ".claude/gen-test-out/byte-identical-2"; + + [Test] + public void Regen_is_deterministic_across_two_invocations() + { + var repoRoot = FindRepoRoot(); + var xmiPath = Path.Combine(repoRoot, XmiRelativePath); + Assert.That(File.Exists(xmiPath), Is.True, + $"XMI snapshot missing at {xmiPath}. Is the build/sysml-model submodule initialized?"); + + var scratchA = Path.Combine(repoRoot, GenScratchDirPrimary); + var scratchB = Path.Combine(repoRoot, GenScratchDirSecondary); + InitScratch(scratchA); + InitScratch(scratchB); + + RunGenerator(repoRoot, xmiPath, scratchA); + RunGenerator(repoRoot, xmiPath, scratchB); + + var hashesA = HashGeneratedTree(Path.Combine(scratchA, "libraries")); + var hashesB = HashGeneratedTree(Path.Combine(scratchB, "libraries")); + + var diff = CompareTrees(hashesA, hashesB); + Assert.That(diff.Length, Is.Zero, + "Regenerator is NOT deterministic: two back-to-back invocations against " + + "the same XMI produced different .g.cs trees. Any Phase 3 template " + + "consolidation that changes the emission surface would flip this test RED.\n\n" + + diff); + } + + [Test] + public void Current_XMI_regen_matches_committed_g_cs_tree() + { + var repoRoot = FindRepoRoot(); + var xmiPath = Path.Combine(repoRoot, XmiRelativePath); + Assert.That(File.Exists(xmiPath), Is.True, + $"XMI snapshot missing at {xmiPath}. Is the build/sysml-model submodule initialized?"); + + var scratchRoot = Path.Combine(repoRoot, GenScratchDirPrimary); + InitScratch(scratchRoot); + RunGenerator(repoRoot, xmiPath, scratchRoot); + + var emitted = HashGeneratedTree(Path.Combine(scratchRoot, "libraries")); + var committed = HashGeneratedTree(Path.Combine(repoRoot, "libraries")); + + var diff = CompareTrees(committed, emitted, leftLabel: "committed", rightLabel: "regenerated"); + Assert.That(diff.Length, Is.Zero, + "Regeneration is not byte-identical to the committed .g.cs tree. Either " + + "the templates changed emission behavior, the parser drifted, or the " + + "committed generated files were hand-edited.\n\n" + diff); + } + + // --- helpers ----------------------------------------------------- + + // Locates the repo root by walking up from the test assembly's base + // directory until a directory containing MTConnect.NET.sln is found. + private static string FindRepoRoot() + { + var current = new DirectoryInfo(AppContext.BaseDirectory); + while (current != null) + { + if (File.Exists(Path.Combine(current.FullName, SlnFileName))) + return current.FullName; + current = current.Parent; + } + throw new DirectoryNotFoundException( + $"Could not locate {SlnFileName} in any ancestor of {AppContext.BaseDirectory}. " + + "The test must run from within the MTConnect.NET repository."); + } + + // Wipes the target directory, then scaffolds the three library + // subdirectories the generator's Program.cs guards its renderer + // entry points on (fail-fast against pointing --output at the + // wrong tree). The generator populates only .g.cs files inside + // these subtrees; hand-authored .cs files live alongside but are + // never emitted, so the scaffolding stays empty. + private static void InitScratch(string path) + { + if (Directory.Exists(path)) + Directory.Delete(path, recursive: true); + Directory.CreateDirectory(path); + Directory.CreateDirectory(Path.Combine(path, "libraries", "MTConnect.NET-Common")); + Directory.CreateDirectory(Path.Combine(path, "libraries", "MTConnect.NET-JSON-cppagent")); + Directory.CreateDirectory(Path.Combine(path, "libraries", "MTConnect.NET-XML")); + } + + // Invokes the generator via `dotnet run --no-build --project + // -- --xmi --output `. The generator project is + // wired as a ProjectReference on this test csproj so MSBuild + // builds it ahead of the test run; --no-build keeps the invocation + // cheap. Non-zero exit fires the caller with the full stdout / + // stderr in the exception. + private static void RunGenerator(string repoRoot, string xmiPath, string scratchRoot) + { + var psi = new ProcessStartInfo("dotnet") + { + WorkingDirectory = repoRoot, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + psi.ArgumentList.Add("run"); + psi.ArgumentList.Add("--no-build"); + psi.ArgumentList.Add("--project"); + psi.ArgumentList.Add(GeneratorProject); + psi.ArgumentList.Add("--"); + psi.ArgumentList.Add("--xmi"); + psi.ArgumentList.Add(xmiPath); + psi.ArgumentList.Add("--output"); + psi.ArgumentList.Add(scratchRoot); + // --full-tree pins the byte-identical guard to the full-regeneration + // path. Without it the zero-config auto-derive (task #408) would + // kick in against the scratch dir, which lacks + // libraries/MTConnect.NET-Common/MTConnectVersions.cs, and abort + // with a PREV_VERSION resolver error before any templates render. + psi.ArgumentList.Add("--full-tree"); + + using var proc = Process.Start(psi) + ?? throw new InvalidOperationException("Failed to start dotnet run for the generator."); + + // Drain stdout AND stderr concurrently. Blocking on ReadToEnd() for + // one pipe while the child writes >4 KB to the other deadlocks + // (Linux pipe buffer fills, child blocks on write, parent blocks on + // read of the empty pipe). Task.WhenAll on the two async reads and + // WaitForExitAsync side-steps the deadlock entirely. + var stdoutTask = proc.StandardOutput.ReadToEndAsync(); + var stderrTask = proc.StandardError.ReadToEndAsync(); + System.Threading.Tasks.Task.WhenAll(stdoutTask, stderrTask).GetAwaiter().GetResult(); + proc.WaitForExit(); + var stdout = stdoutTask.Result; + var stderr = stderrTask.Result; + + if (proc.ExitCode != 0) + { + throw new InvalidOperationException( + $"Generator exited with code {proc.ExitCode}.\n" + + $"stdout:\n{stdout}\n" + + $"stderr:\n{stderr}"); + } + } + + // Walks the tree, hashing every .g.cs file. Returns a dictionary + // keyed by the path relative to (forward-slash normalised) + // with the SHA-256 hash of the file's byte content as value. + // + // MSBuild-generated intermediates under bin/ and obj/ (a library's + // GlobalUsings.g.cs from Microsoft.NET.Sdk.CSharp.CoreCompile.targets, + // ImplicitNamespaceImports.g.cs, etc.) are skipped — the generator + // never touches them, and their presence would spuriously flip this + // test RED on any host that has already built the solution. + private static Dictionary HashGeneratedTree(string root) + { + var result = new Dictionary(StringComparer.Ordinal); + if (!Directory.Exists(root)) + return result; + + using var sha = SHA256.Create(); + foreach (var file in Directory.EnumerateFiles(root, "*.g.cs", SearchOption.AllDirectories)) + { + var relative = Path.GetRelativePath(root, file).Replace('\\', '/'); + if (relative.Contains("/bin/") || relative.Contains("/obj/") || + relative.StartsWith("bin/") || relative.StartsWith("obj/")) + continue; + using var stream = File.OpenRead(file); + result[relative] = sha.ComputeHash(stream); + } + return result; + } + + // Emits a human-readable diff report between two path -> hash + // dictionaries. Returns an empty string when the two are identical. + private static string CompareTrees( + Dictionary left, + Dictionary right, + string leftLabel = "expected", + string rightLabel = "actual") + { + var onlyLeft = left.Keys.Except(right.Keys).OrderBy(k => k).ToList(); + var onlyRight = right.Keys.Except(left.Keys).OrderBy(k => k).ToList(); + var mismatched = left.Keys.Intersect(right.Keys) + .Where(k => !left[k].SequenceEqual(right[k])) + .OrderBy(k => k) + .ToList(); + + var report = new StringBuilder(); + AppendListing(report, $"Missing in {rightLabel} (present in {leftLabel})", onlyLeft); + AppendListing(report, $"Extra in {rightLabel} (absent from {leftLabel})", onlyRight); + AppendListing(report, "Content mismatch", mismatched); + return report.ToString(); + } + + private static void AppendListing(StringBuilder sink, string heading, List entries) + { + if (entries.Count == 0) + return; + + sink.AppendLine($"{heading} ({entries.Count} files):"); + foreach (var path in entries.Take(20)) + sink.AppendLine($" {path}"); + if (entries.Count > 20) + sink.AppendLine($" ... and {entries.Count - 20} more"); + } + } +} diff --git a/tests/MTConnect.NET-Generator-Tests/CliInvocationFailureTests.cs b/tests/MTConnect.NET-Generator-Tests/CliInvocationFailureTests.cs new file mode 100644 index 000000000..9bca02f19 --- /dev/null +++ b/tests/MTConnect.NET-Generator-Tests/CliInvocationFailureTests.cs @@ -0,0 +1,528 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using NUnit.Framework; + +namespace MTConnect.NET_Generator_Tests +{ + /// + /// CLI failure-path coverage for the SysML importer's Program.cs. + /// + /// + /// The importer's happy path (full-tree regen + delta regen) is covered + /// by and . + /// This fixture pins the EARLY-RETURN branches — every documented exit + /// code, every invalid-input surface, and the two RequireValue + /// throws that fire when a flag arrives without its trailing value. + /// + /// + /// + /// Every case is exercised end-to-end via dotnet run --no-build + /// --project build/MTConnect.NET-SysML-Import so the assertions bind + /// to the CLI contract the operator actually sees, not to an internal + /// helper. Exit codes are documented in the Program.cs header: + /// + /// 0 — success (including --help / -h). + /// 1 — runtime failure (file not found, parse null, missing library subdir). + /// 2 — usage failure (missing / unknown flag). + /// + /// + /// + /// + /// Extra runtime failures (RequireValue throws on a dangling + /// flag, MTConnectModel.Parse returns null on a malformed XMI, + /// a missing library subdirectory throws DirectoryNotFoundException) + /// surface as non-zero exit codes; the assertions there are on + /// ExitCode != 0 plus the stderr fingerprint, since the .NET + /// runtime unhandled-exception exit code (0x80000000-ish, negative + /// signed) is host-dependent. + /// + /// + [TestFixture] + public class CliInvocationFailureTests + { + private const string SlnFileName = "MTConnect.NET.sln"; + private const string GeneratorProject = "build/MTConnect.NET-SysML-Import"; + private const string XmiRelativePath = "build/sysml-model/MTConnectSysMLModel.xml"; + private const string ScratchRoot = ".claude/gen-test-out/cli-failure"; + + [Test] + public void Unknown_flag_exits_2_and_stderr_names_the_flag() + { + var (exitCode, _, stderr) = Run("--not-a-real-flag"); + Assert.That(exitCode, Is.EqualTo(2), + "Unknown flags are a usage error; exit 2 is the documented contract."); + Assert.That(stderr, Does.Contain("Unknown argument"), + "stderr should name the flag class so the operator sees a discoverable message."); + Assert.That(stderr, Does.Contain("--not-a-real-flag"), + "stderr should echo the offending flag verbatim."); + } + + [Test] + public void Missing_xmi_flag_exits_2_with_required_message() + { + var scratch = InitScratch("missing-xmi"); + var (exitCode, _, stderr) = Run("--output", scratch); + Assert.That(exitCode, Is.EqualTo(2), + "Missing --new-xmi is a usage error; exit 2."); + Assert.That(stderr, Does.Contain("--new-xmi"), + "stderr should identify which required flag is missing."); + Assert.That(stderr, Does.Contain("--xmi"), + "stderr should also mention the legacy --xmi alias so operators grepping for the pre-#233 flag name still see the required-flag hint."); + Assert.That(stderr, Does.Contain("required"), + "stderr should call out that the flag is required."); + } + + [Test] + public void Missing_output_flag_exits_2_with_required_message() + { + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + var (exitCode, _, stderr) = Run("--xmi", xmi); + Assert.That(exitCode, Is.EqualTo(2), + "Missing --output is a usage error; exit 2."); + Assert.That(stderr, Does.Contain("--output"), + "stderr should identify which required flag is missing."); + } + + [Test] + public void Nonexistent_xmi_file_exits_1_with_not_found_message() + { + var scratch = InitScratch("nonexistent-xmi"); + var bogusXmi = Path.Combine(scratch, "does-not-exist.xml"); + var (exitCode, _, stderr) = Run("--xmi", bogusXmi, "--output", scratch); + Assert.That(exitCode, Is.EqualTo(1), + "Missing XMI file is a runtime failure; exit 1."); + Assert.That(stderr, Does.Contain("XMI file not found"), + "stderr should name the failure class so the operator can act."); + Assert.That(stderr, Does.Contain(bogusXmi), + "stderr should echo the resolved path so a typo is grep-able."); + } + + [Test] + public void Nonexistent_previous_xmi_file_exits_1_with_not_found_message() + { + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + var scratch = InitScratch("nonexistent-previous-xmi"); + var bogusPrev = Path.Combine(scratch, "does-not-exist-prev.xml"); + var (exitCode, _, stderr) = Run("--xmi", xmi, "--previous-xmi", bogusPrev, "--output", scratch); + Assert.That(exitCode, Is.EqualTo(1), + "Missing --previous-xmi file is a runtime failure; exit 1."); + Assert.That(stderr, Does.Contain("--previous-xmi file not found"), + "stderr should name the exact flag whose target is missing."); + Assert.That(stderr, Does.Contain(bogusPrev), + "stderr should echo the resolved path."); + } + + [Test] + public void Nonexistent_output_root_exits_1_with_not_found_message() + { + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + var bogusOutput = Path.Combine(repoRoot, ScratchRoot, "does-not-exist-output"); + // Deliberately do NOT create bogusOutput's directory. + if (Directory.Exists(bogusOutput)) + Directory.Delete(bogusOutput, recursive: true); + var (exitCode, _, stderr) = Run("--xmi", xmi, "--output", bogusOutput); + Assert.That(exitCode, Is.EqualTo(1), + "Missing output root is a runtime failure; exit 1."); + Assert.That(stderr, Does.Contain("Output root not found"), + "stderr should identify the output-root failure class."); + } + + [Test] + public void Help_flag_exits_0_and_stdout_carries_usage_banner() + { + var (exitCode, stdout, _) = Run("--help"); + Assert.That(exitCode, Is.Zero, + "--help is a documented success path; exit 0."); + Assert.That(stdout, Does.Contain("MTConnect.NET SysML Importer"), + "Help output must carry the tool banner so the operator knows what they're using."); + Assert.That(stdout, Does.Contain("--new-xmi"), + "Help must list --new-xmi (preferred flag; task #408)."); + Assert.That(stdout, Does.Contain("--xmi"), + "Help must also mention --xmi (legacy alias documented for pre-#408 callers)."); + Assert.That(stdout, Does.Contain("--previous-xmi"), + "Help must list --previous-xmi (added in Phase 4.3)."); + Assert.That(stdout, Does.Contain("--compat-version-label"), + "Help must list --compat-version-label (added in Phase 4.3)."); + Assert.That(stdout, Does.Contain("--full-tree"), + "Help must list --full-tree (added in task #408 as the escape hatch that disables both delta paths)."); + } + + [Test] + public void Short_help_flag_exits_0() + { + var (exitCode, stdout, _) = Run("-h"); + Assert.That(exitCode, Is.Zero, "-h is the short form of --help; exit 0."); + Assert.That(stdout, Does.Contain("MTConnect.NET SysML Importer"), + "-h must produce the same banner as --help."); + } + + [Test] + public void Missing_value_after_xmi_flag_exits_non_zero_with_argument_exception() + { + // RequireValue throws ArgumentException when the flag is the last + // token and no value follows. The unhandled exception bubbles to + // the CLR host and returns a non-zero exit code; the stderr + // fingerprint carries the ArgumentException message. + var (exitCode, _, stderr) = Run("--xmi"); + Assert.That(exitCode, Is.Not.Zero, + "A flag with no trailing value is a runtime failure; exit must be non-zero."); + Assert.That(stderr, Does.Contain("--xmi"), + "stderr should name the offending flag."); + Assert.That(stderr, Does.Contain("requires a value").Or.Contain("ArgumentException"), + "stderr should carry the RequireValue-throw fingerprint."); + } + + [Test] + public void Missing_value_after_new_xmi_flag_exits_non_zero() + { + // Task #408 introduced --new-xmi as the preferred spelling. Its + // RequireValue arm is a distinct switch case from --xmi; pin the + // parallel failure surface so a later refactor can't silently + // regress the preferred-flag arm while leaving the legacy alias + // exercised. + var (exitCode, _, stderr) = Run("--new-xmi"); + Assert.That(exitCode, Is.Not.Zero, + "A --new-xmi with no trailing value is a runtime failure; exit non-zero."); + Assert.That(stderr, Does.Contain("--new-xmi"), + "stderr should name the offending flag verbatim."); + Assert.That(stderr, Does.Contain("requires a value").Or.Contain("ArgumentException"), + "stderr should carry the RequireValue-throw fingerprint."); + } + + [Test] + public void Missing_value_after_previous_xmi_flag_exits_non_zero() + { + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + // --previous-xmi is the last token; RequireValue throws. + var (exitCode, _, stderr) = Run("--xmi", xmi, "--previous-xmi"); + Assert.That(exitCode, Is.Not.Zero, + "A --previous-xmi with no trailing value is a runtime failure; exit non-zero."); + Assert.That(stderr, Does.Contain("--previous-xmi"), + "stderr should name the offending flag."); + } + + [Test] + public void Missing_value_after_compat_version_label_exits_non_zero() + { + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + var (exitCode, _, stderr) = Run("--xmi", xmi, "--compat-version-label"); + Assert.That(exitCode, Is.Not.Zero, + "A --compat-version-label with no trailing value is a runtime failure; exit non-zero."); + Assert.That(stderr, Does.Contain("--compat-version-label"), + "stderr should name the offending flag."); + } + + [Test] + public void Missing_value_after_output_flag_exits_non_zero() + { + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + var (exitCode, _, stderr) = Run("--xmi", xmi, "--output"); + Assert.That(exitCode, Is.Not.Zero, + "A --output with no trailing value is a runtime failure; exit non-zero."); + Assert.That(stderr, Does.Contain("--output"), + "stderr should name the offending flag."); + } + + [Test] + public void Missing_value_after_json_dump_flag_exits_non_zero() + { + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + var (exitCode, _, stderr) = Run("--xmi", xmi, "--json-dump"); + Assert.That(exitCode, Is.Not.Zero, + "A --json-dump with no trailing value is a runtime failure; exit non-zero."); + Assert.That(stderr, Does.Contain("--json-dump"), + "stderr should name the offending flag."); + } + + [Test] + public void Missing_library_subdirectory_under_output_root_throws() + { + // Output root exists, but the required libraries/MTConnect.NET-Common + // subdirectory is absent. Program's RenderCommonClasses fails + // fast with a DirectoryNotFoundException. Pass --full-tree so the + // zero-config auto-derive path doesn't intercept first with its + // own "MTConnectVersions.cs not found" surface — this fixture is + // pinning the RenderCommonClasses failure, not the auto-derive + // failure (that path is covered by AutoDerivePreviousXmiTests). + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + var scratch = InitScratch("missing-lib-subdir"); + // Deliberately do NOT create the libraries/MTConnect.NET-Common subdir. + var (exitCode, _, stderr) = Run("--xmi", xmi, "--output", scratch, "--full-tree"); + Assert.That(exitCode, Is.Not.Zero, + "A missing library subdirectory must fail fast, not silently no-op."); + Assert.That(stderr, Does.Contain("MTConnect.NET-Common").Or.Contain("DirectoryNotFoundException"), + "stderr should identify which subdir is missing so the operator can create it."); + } + + [Test] + public void Malformed_xmi_exits_non_zero_and_surfaces_parse_failure() + { + var scratch = InitScratchWithLibraries("malformed-xmi"); + var badXmi = Path.Combine(scratch, "malformed.xml"); + // A well-formed XML that is not a SysML XMI. Two possible + // surface behaviors: + // (a) MTConnectModel.Parse returns null → Program's full-tree + // branch prints "error: Failed to parse XMI" and returns 1. + // (b) MTConnectModel.Parse throws (missing UML root element, + // unhandled KeyNotFoundException, etc.) → the CLR host + // returns a non-zero abnormal-termination exit code + // (typically 134 on Linux, i.e. SIGABRT from an unhandled + // exception). + // Both surfaces satisfy the coverage contract "malformed input is + // a runtime failure". The (a) branch is the graceful, operator- + // friendly one and would be a nice hardening target (a top-level + // try/catch that mapped every parse exception to `return 1;`); + // that hardening is tracked as a follow-up finding. + File.WriteAllText(badXmi, ""); + // --full-tree so the parse failure lands in the full-tree branch, not + // in the zero-config auto-derive's PREV_VERSION resolver — this + // fixture is pinning the parse-failure surface, not the auto-derive + // one (that path is covered by AutoDerivePreviousXmiTests). + var (exitCode, stdout, stderr) = Run("--xmi", badXmi, "--output", scratch, "--full-tree"); + Assert.That(exitCode, Is.Not.Zero, + $"A malformed XMI must fail the invocation. exit={exitCode}\nstdout:\n{stdout}\nstderr:\n{stderr}"); + var combined = stdout + "\n" + stderr; + Assert.That(combined, + Does.Contain("Failed to parse XMI") + .Or.Contain("parse") + .Or.Contain("Exception") + .Or.Contain("XmlException") + .Or.Contain("NullReference"), + "The output stream must surface a parse-failure fingerprint the operator can grep for."); + } + + // Every hostile / malformed --compat-version-label value that + // IsSafeCompatLabel is designed to reject. Each case exercises the + // exit-2 guard branch (Program.cs:198-204). The regex accepts + // 1..64 chars of [A-Za-z0-9_\-] followed by [A-Za-z0-9_\-.]*, no + // leading dot; anything else must reject at argument-parse time. + // + // The `TestCaseSource` shape (versus inline `[TestCase]`) keeps the + // 65-char oversize label programmatically constructed rather than + // hard-coded, so a later ratchet of the length limit needs to + // change only the source method + the guard. + [TestCaseSource(nameof(HostileCompatLabelCases))] + public void Hostile_compat_version_label_rejects_with_exit_2( + string hostileLabel, string scenario) + { + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + var scratch = InitScratchWithLibraries($"hostile-label-{scenario}"); + + // --full-tree short-circuits the auto-derive resolver so the + // safety check is exercised in isolation. Without --full-tree + // the zero-config resolver would abort first (no + // MTConnectVersions.cs under the scratch tree), masking the + // IsSafeCompatLabel branch under a different early-return. + var (exitCode, _, stderr) = Run( + "--xmi", xmi, + "--output", scratch, + "--compat-version-label", hostileLabel, + "--full-tree"); + + Assert.That(exitCode, Is.EqualTo(2), + $"Hostile --compat-version-label '{hostileLabel}' ({scenario}) must reject with usage-error exit 2. " + + $"An exit 0/1 signals the IsSafeCompatLabel guard was bypassed. stderr:\n{stderr}"); + Assert.That(stderr, Does.Contain("--compat-version-label"), + "stderr must name the offending flag so the operator sees which value the parser rejected."); + Assert.That(stderr, Does.Contain("not a safe filename"), + "stderr must carry the guard's rejection fingerprint (`not a safe filename`) " + + "so the operator distinguishes label-shape rejection from other exit-2 causes."); + } + + // Enumerates the hostile-label surface. Each entry is + // (label, scenario-slug); the slug feeds the scratch-dir suffix so + // parallel runs don't collide. Every entry must reject via + // IsSafeCompatLabel returning false. + private static object[] HostileCompatLabelCases() + { + return new object[] + { + new object[] { "../etc/passwd", "path-traversal-parent" }, + new object[] { "Compat/../secret", "path-traversal-inline" }, + new object[] { "sub/dir", "forward-slash" }, + new object[] { "sub\\dir", "backslash" }, + new object[] { ".hidden", "leading-dot" }, + new object[] { "..", "double-dot" }, + new object[] { " ", "whitespace-only" }, + new object[] { "with space", "internal-space" }, + new object[] { "label;drop", "semicolon-injection" }, + new object[] { "label$var", "shell-metachar" }, + new object[] { "label|pipe", "pipe" }, + new object[] { "label\ttab", "control-tab" }, + new object[] { new string('A', 65), "over-length" }, + }; + } + + [Test] + public void Empty_compat_version_label_rejects_with_exit_2() + { + // An empty string satisfies the flag-has-a-value check (RequireValue + // returns "" rather than throwing) but must fail the safety guard + // (IsNullOrWhiteSpace short-circuits IsSafeCompatLabel to false). + // This is the boundary case for the length-lower-bound arm. + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + var scratch = InitScratchWithLibraries("hostile-label-empty"); + var (exitCode, _, stderr) = Run( + "--xmi", xmi, + "--output", scratch, + "--compat-version-label", "", + "--full-tree"); + Assert.That(exitCode, Is.EqualTo(2), + $"An empty --compat-version-label must reject with usage-error exit 2. stderr:\n{stderr}"); + Assert.That(stderr, Does.Contain("not a safe filename"), + "stderr must carry the guard's rejection fingerprint."); + } + + // Safe-label positive cases — every documented default and every + // pattern the auto-derive machinery emits must PASS the guard so a + // ratchet of the regex (accidentally tightening it) can't silently + // regress the happy path. + [TestCase("Previous")] + [TestCase("v2_7")] + [TestCase("v10_15")] + [TestCase("Release-2.6.0")] + [TestCase("a")] + // 64-char boundary case: 26 upper + 26 lower + 10 digits + `_-` = 64. + // Exercises the length-upper-bound `label.Length > 64` arm at its + // exact accept-side boundary. + [TestCase("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789__")] + public void Safe_compat_version_label_accepts_and_reaches_full_tree_branch(string safeLabel) + { + // Boundary: the last case is exactly 64 chars — the length-upper + // bound. IsSafeCompatLabel rejects >64 but must accept ==64. + Assert.That(safeLabel.Length, Is.LessThanOrEqualTo(64), + "Test setup invariant — safe labels sit inside the length window."); + + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + // Sanitise the label for the scratch-dir suffix (the label may + // contain '.' which is legal in filenames but collides with the + // dir-slug convention). Replace non-alnum with '_'. + var scratchSuffix = "safe-label-" + System.Text.RegularExpressions.Regex.Replace(safeLabel, @"[^A-Za-z0-9]", "_"); + if (scratchSuffix.Length > 96) scratchSuffix = scratchSuffix[..96]; + var scratch = InitScratchWithLibraries(scratchSuffix); + + var (exitCode, _, stderr) = Run( + "--xmi", xmi, + "--output", scratch, + "--compat-version-label", safeLabel, + "--full-tree"); + + Assert.That(exitCode, Is.Zero, + $"Safe --compat-version-label '{safeLabel}' must not be rejected by the guard. stderr:\n{stderr}"); + Assert.That(stderr, Does.Not.Contain("not a safe filename"), + "stderr must not carry the guard rejection message for a safe label."); + } + + [Test] + public void JsonDump_writes_the_dump_file_when_flag_supplied() + { + var repoRoot = FindRepoRoot(); + var xmi = Path.Combine(repoRoot, XmiRelativePath); + var scratch = InitScratchWithLibraries("json-dump"); + var dumpPath = Path.Combine(scratch, "model.json"); + // --full-tree so the JSON-dump path is exercised without the + // zero-config auto-derive stepping in (which would resolve to the + // same-tree v2.7 XMI and successfully run delta mode, wasting time + // on a delta the test doesn't assert against). + var (exitCode, stdout, stderr) = Run("--xmi", xmi, "--output", scratch, "--json-dump", dumpPath, "--full-tree"); + Assert.That(exitCode, Is.Zero, + $"--json-dump plus a valid XMI + output should succeed.\nstdout:\n{stdout}\nstderr:\n{stderr}"); + Assert.That(File.Exists(dumpPath), Is.True, + "The dump file should exist at the requested path."); + var dumpContent = File.ReadAllText(dumpPath); + Assert.That(dumpContent.Length, Is.GreaterThan(1024), + "The dump content must be a non-trivial JSON tree, not an empty file."); + Assert.That(dumpContent.TrimStart(), Does.StartWith("{"), + "The dump content must start as a JSON object."); + Assert.That(stdout, Does.Contain("JSON dump: writing to"), + "stdout should echo the resolved dump path so the operator can verify placement."); + } + + // --- helpers ----------------------------------------------------- + + private static string FindRepoRoot() + { + var current = new DirectoryInfo(AppContext.BaseDirectory); + while (current != null) + { + if (File.Exists(Path.Combine(current.FullName, SlnFileName))) + return current.FullName; + current = current.Parent; + } + throw new DirectoryNotFoundException( + $"Could not locate {SlnFileName} in any ancestor of {AppContext.BaseDirectory}."); + } + + // Creates the scratch dir root without library subdirectories. Used + // when the test needs a "valid output-root path that lacks the + // library scaffolding" (exercises the throw path in + // RenderCommonClasses / RenderJsonComponents / RenderXmlComponents). + private static string InitScratch(string suffix) + { + var repoRoot = FindRepoRoot(); + var path = Path.Combine(repoRoot, ScratchRoot, suffix); + if (Directory.Exists(path)) + Directory.Delete(path, recursive: true); + Directory.CreateDirectory(path); + return path; + } + + // Creates the scratch dir root PLUS the three library subdirectories + // the generator's full-tree branch guards against. Used for the + // happy-path adjacent cases (malformed XMI, JSON-dump). + private static string InitScratchWithLibraries(string suffix) + { + var path = InitScratch(suffix); + Directory.CreateDirectory(Path.Combine(path, "libraries", "MTConnect.NET-Common")); + Directory.CreateDirectory(Path.Combine(path, "libraries", "MTConnect.NET-JSON-cppagent")); + Directory.CreateDirectory(Path.Combine(path, "libraries", "MTConnect.NET-XML")); + return path; + } + + private static (int ExitCode, string Stdout, string Stderr) Run(params string[] cliArgs) + { + var repoRoot = FindRepoRoot(); + var psi = new ProcessStartInfo("dotnet") + { + WorkingDirectory = repoRoot, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + psi.ArgumentList.Add("run"); + psi.ArgumentList.Add("--no-build"); + psi.ArgumentList.Add("--project"); + psi.ArgumentList.Add(GeneratorProject); + psi.ArgumentList.Add("--"); + foreach (var arg in cliArgs) + psi.ArgumentList.Add(arg); + + using var proc = Process.Start(psi) + ?? throw new InvalidOperationException("Failed to start dotnet run for the generator."); + + // Drain stdout and stderr concurrently — see ByteIdenticalRegenTests + // for the deadlock defense this pattern encodes. + var stdoutTask = proc.StandardOutput.ReadToEndAsync(); + var stderrTask = proc.StandardError.ReadToEndAsync(); + System.Threading.Tasks.Task.WhenAll(stdoutTask, stderrTask).GetAwaiter().GetResult(); + proc.WaitForExit(); + return (proc.ExitCode, stdoutTask.Result, stderrTask.Result); + } + } +} diff --git a/tests/MTConnect.NET-Generator-Tests/DeltaCompatAndStatsTests.cs b/tests/MTConnect.NET-Generator-Tests/DeltaCompatAndStatsTests.cs new file mode 100644 index 000000000..202a9ffe1 --- /dev/null +++ b/tests/MTConnect.NET-Generator-Tests/DeltaCompatAndStatsTests.cs @@ -0,0 +1,352 @@ +// Copyright (c) 2026 TrakHound Inc., All Rights Reserved. +// TrakHound Inc. licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using NUnit.Framework; + +namespace MTConnect.NET_Generator_Tests +{ + /// + /// Delta-mode invariants that does not + /// cover: the Compat file's header + multi-namespace concentration, the + /// --compat-version-label default ("Previous"), and the + /// stdout stats line's per-category counter reporting. + /// + /// + /// The plan-D4 contract for the concentrated Compat file is: + /// + /// Prefixed with the TrakHound copyright + MIT licence header. + /// Each concentrated block introduced by a + /// // --- from <relative-path> --- divider and prefixed by + /// the source file's original body verbatim (including its + /// namespace X { ... } block, since multi-namespace + /// concentration is legal C#). + /// Byte-identical to the source file's body for every UNCHANGED + /// entry (so git diff shows zero drift after a rebuild). + /// + /// + /// + /// + /// The stdout stats line is the operator's telemetry surface: every + /// invocation prints Delta emission: added=N, changed=N, + /// unchanged-concentrated=N, removed-skipped=N, compat-files-written=N + /// so a spec bump's shape is grep-able. Pinning the format keeps the + /// operator-facing contract explicit; a silent rename of any counter + /// key would flip these tests RED. + /// + /// + [TestFixture] + public class DeltaCompatAndStatsTests + { + private const string SlnFileName = "MTConnect.NET.sln"; + private const string GeneratorProject = "build/MTConnect.NET-SysML-Import"; + private const string XmiRelativePath = "build/sysml-model/MTConnectSysMLModel.xml"; + private const string ScratchRoot = ".claude/gen-test-out/delta-compat"; + + [Test] + public void Same_XMI_stats_line_reports_zero_added_changed_removed_and_positive_unchanged() + { + var repoRoot = FindRepoRoot(); + var xmiPath = Path.Combine(repoRoot, XmiRelativePath); + var scratch = InitScratch("same-stats"); + + var (exitCode, stdout, stderr) = RunDelta(xmiPath, previousXmiPath: xmiPath, + compatLabel: "Baseline", output: scratch); + Assert.That(exitCode, Is.Zero, $"Generator exited non-zero.\nstdout:\n{stdout}\nstderr:\n{stderr}"); + + var stats = ParseStatsLine(stdout); + Assert.That(stats.Added, Is.Zero, "Same XMI on both sides: no ADDED files."); + Assert.That(stats.Changed, Is.Zero, "Same XMI on both sides: no CHANGED files."); + Assert.That(stats.RemovedSkipped, Is.Zero, "Same XMI on both sides: no REMOVED files."); + Assert.That(stats.UnchangedConcentrated, Is.GreaterThan(0), + "Same XMI on both sides: every emitted file goes into the UNCHANGED-concentrated partition."); + Assert.That(stats.CompatFilesWritten, Is.EqualTo(3), + "Same XMI on both sides: one Compat/