316 lines
17 KiB
Markdown
316 lines
17 KiB
Markdown
|
|
---
|
|||
|
|
source_files:
|
|||
|
|
- Common/DTS.Common.Serialization/Test/IConvertable.cs
|
|||
|
|
- Common/DTS.Common.Serialization/Test/IntervalSec.cs
|
|||
|
|
- Common/DTS.Common.Serialization/Test/DasTimestamp.cs
|
|||
|
|
- Common/DTS.Common.Serialization/Test/Test.cs
|
|||
|
|
generated_at: "2026-04-16T03:35:54.397147+00:00"
|
|||
|
|
model: "Qwen/Qwen3-Coder-Next-FP8"
|
|||
|
|
schema_version: 1
|
|||
|
|
sha256: "d172f5c36f1bfbab"
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Documentation: `DTS.Serialization` Namespace – Serialization Types
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. Purpose
|
|||
|
|
|
|||
|
|
This module provides core serialization infrastructure for test metadata in the DTS system, centered around the `Test` class and its associated types (`DasTimestamp`, `IntervalSec`, and the `IConvertable` interface). It enables structured XML serialization/deserialization of test metadata (e.g., test ID, description, modules, channels, DAS timestamps), supports equality comparison, and includes utilities for channel ordering and fault flag management. The module exists to standardize how test metadata is persisted, retrieved, and compared across the DTS ecosystem, particularly for interoperability with SLICEWare and internal tools.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Public Interface
|
|||
|
|
|
|||
|
|
### `IConvertable` Interface
|
|||
|
|
*Defined in `IConvertable.cs`*
|
|||
|
|
|
|||
|
|
- **`Test ToDtsSerializationTest()`**
|
|||
|
|
Converts the implementing object into a `DTS.Serialization.Test` instance.
|
|||
|
|
|
|||
|
|
- **`void FromDtsSerializationTest(Test test, ReportErrors reportErrors)`**
|
|||
|
|
Initializes the implementing object using data from a `Test` instance. Errors encountered during conversion are reported via the `reportErrors` delegate.
|
|||
|
|
|
|||
|
|
> **Note**: `ReportErrors` is a delegate: `public delegate void ReportErrors(List<string> errors);`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### `Test` Class
|
|||
|
|
*Defined in `Test.cs`*
|
|||
|
|
|
|||
|
|
- **Constructors**
|
|||
|
|
- `Test()`
|
|||
|
|
Default constructor. Initializes `InceptionDate` to `DateTime.Now`, calls `TryGetChannelOrder()`, and leaves `Id` and `Description` empty.
|
|||
|
|
- `Test(string dtsfile)`
|
|||
|
|
Placeholder constructor (empty implementation).
|
|||
|
|
- `Test(string id, string description)`
|
|||
|
|
Initializes with `id`, `description`, and `EventNumber = 0`.
|
|||
|
|
- `Test(string id, string description, int eventNumber)`
|
|||
|
|
Initializes with `id`, `description`, and `eventNumber`.
|
|||
|
|
|
|||
|
|
- **Properties**
|
|||
|
|
- `string Software` → `"DataPRO"` by default (read/write, XML-serialized as `"Software"`).
|
|||
|
|
- `string SoftwareVersion` → `""` by default (read/write, XML-serialized as `"SoftwareVersion"`).
|
|||
|
|
- `DateTime InceptionDate` → `DateTime.Now` by default (read/write).
|
|||
|
|
- `string Id` → `""` by default (read/write, XML-serialized as `"Id"`).
|
|||
|
|
- `string Description` → `""` by default (read/write, XML-serialized as `"Description"`).
|
|||
|
|
- `int EventNumber` → `0` by default (read/write, XML-serialized as `"EventNumber"`).
|
|||
|
|
- `Guid Guid` → `Guid.Empty` by default (read/write, XML-serialized as `"Guid"`).
|
|||
|
|
- `ushort FaultFlags` → `0` by default (read/write, XML-serialized as `"FaultFlags"`).
|
|||
|
|
- `uint ExtendedFaultFlags1–4` → `0` by default (read/write, XML-serialized as `"ExtendedFaultFlags1"`–`"ExtendedFaultFlags4"`).
|
|||
|
|
- `bool InlineSerializedData` → `false` by default (read/write, XML-serialized as `"InlineSerializedData"`; setting it propagates to all `Modules`).
|
|||
|
|
- `List<Module> Modules` → empty list by default (read/write, XML-serialized as `"Modules"`).
|
|||
|
|
- `List<DasTimestamp> DasTimestamps` → empty list by default (read/write, XML-serialized as `"DasTimestamps"`).
|
|||
|
|
- `List<Module.Channel> Channels` → computed list of all channels (including calculated channels) from `Modules`, sorted by `AbsoluteDisplayOrder`, then `ParentModule.Number`, then `Channel.Number`, and finally by `ChannelOrder.txt` if present.
|
|||
|
|
|
|||
|
|
- **Methods**
|
|||
|
|
- `void ClearExtendedFaultFlags()`
|
|||
|
|
Resets `ExtendedFaultFlags1`–`4` to `0`.
|
|||
|
|
- `void TryGetChannelOrder()`
|
|||
|
|
Attempts to load channel ordering from `"ChannelOrder.txt"` (if present) into an internal dictionary `_channelOrder`. Logs exceptions via `APILogger`.
|
|||
|
|
- `void SaveTest(string directory, string testId, int defaultEncoding, bool includeGroupNameInISOExport)`
|
|||
|
|
Saves test metadata to a `.dts` file. Backs up existing `.dts` file (if no `.bak` exists), writes SLICEWare-compatible data via `SliceRaw.File.Exporter.Write(...)`, then appends XML-serialized `<Test>` metadata (using `WriteXml`) in UTF-16 encoding. Deletes backup on successful save.
|
|||
|
|
- `void WriteXml(XmlWriter writer)`
|
|||
|
|
Serializes the `Test` instance to XML using attributes tagged with `[XmlSerializationTag]`. Writes attributes for top-level properties, then `<Modules>` and `<DasTimestamps>` elements with nested content.
|
|||
|
|
- `void ReadXml(XmlReader reader)`
|
|||
|
|
Deserializes XML into the `Test` instance. Reads attributes for top-level properties, then deserializes `<Module>` and `<DasTimestamp>` children using their respective `ReadXml` methods. Uses `ReadSubtree()` to isolate child element parsing.
|
|||
|
|
- `XmlSchema GetSchema()`
|
|||
|
|
Returns `null` (per comment, this method is never invoked during serialization).
|
|||
|
|
- `override bool Equals(object obj)`
|
|||
|
|
Compares `Id`, `Description`, and `Modules` (via private helper `ModulesEquals`) for equality.
|
|||
|
|
- `override int GetHashCode()`
|
|||
|
|
Returns `base.GetHashCode()` (no custom hashing logic).
|
|||
|
|
|
|||
|
|
> **Note**: `ModulesEquals` compares two `List<Module>` by count and element-wise `Equals`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### `DasTimestamp` Class
|
|||
|
|
*Defined in `DasTimestamp.cs`*
|
|||
|
|
|
|||
|
|
- **Constructor**
|
|||
|
|
- `DasTimestamp(Test parentTest)`
|
|||
|
|
Initializes with a reference to the parent `Test` instance.
|
|||
|
|
|
|||
|
|
- **Properties**
|
|||
|
|
- `Test ParentTest` → `null` by default (read-only, set only via constructor).
|
|||
|
|
- `string BaseSerialNumber` → `""` by default (read/write, XML-serialized as `"BaseSerialNumber"`).
|
|||
|
|
- `UInt64 NumberOfSamples` → `0` by default (read/write, XML-serialized as `"NumberOfSamples"`).
|
|||
|
|
- `UInt32 NumberOfBitsPerSample` → `0` by default (read/write, XML-serialized as `"NumberOfBitsPerSample"`).
|
|||
|
|
- `string FileName` → `""` by default (read/write, XML-serialized as `"FileName"`).
|
|||
|
|
|
|||
|
|
- **Methods**
|
|||
|
|
- `void WriteXml(XmlWriter writer)`
|
|||
|
|
Serializes `BaseSerialNumber`, `NumberOfSamples`, and `NumberOfBitsPerSample` as XML attributes. Writes `BaseSerialNumber` as `"NA"` if conversion fails. *Does not serialize `FileName` or `NumberOfBitsPerSample` in XML output* (only reads `NumberOfBitsPerSample`; defaults to `8 * sizeof(ulong)` if missing).
|
|||
|
|
- `void ReadXml(XmlReader reader)`
|
|||
|
|
Reads `BaseSerialNumber`, `NumberOfSamples`, and `NumberOfBitsPerSample` from attributes. Sets `NumberOfBitsPerSample` to `8 * sizeof(ulong)` (i.e., `64`) if missing or unparseable.
|
|||
|
|
- `XmlSchema GetSchema()`
|
|||
|
|
Returns `null`.
|
|||
|
|
- `override bool Equals(object obj)`
|
|||
|
|
Compares `FileName`, `NumberOfSamples`, `NumberOfBitsPerSample`, and `BaseSerialNumber`.
|
|||
|
|
- `override int GetHashCode()`
|
|||
|
|
Returns `base.GetHashCode()`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### `IntervalSec` Class
|
|||
|
|
*Defined in `IntervalSec.cs`*
|
|||
|
|
|
|||
|
|
- **Constructors**
|
|||
|
|
- `IntervalSec()`
|
|||
|
|
Default constructor. Leaves `Begin` and `End` uninitialized (default `0.0`).
|
|||
|
|
- `IntervalSec(double begin, double end)`
|
|||
|
|
Initializes `Begin` and `End` to specified values. Wraps exceptions in a new `Exception`.
|
|||
|
|
|
|||
|
|
- **Properties**
|
|||
|
|
- `bool DoRoundOffValues` → `false` by default (read/write).
|
|||
|
|
- `int NumberRoundingDecimalPlaces` → `6` by default (read/write, via `Property<int>` wrapper).
|
|||
|
|
- `double Begin` → `0.0` by default (read/write).
|
|||
|
|
*Rounds to `NumberRoundingDecimalPlaces` if `DoRoundOffValues` is `true`.*
|
|||
|
|
- `double End` → `0.0` by default (read/write).
|
|||
|
|
*Rounds to `NumberRoundingDecimalPlaces` if `DoRoundOffValues` is `true`.*
|
|||
|
|
|
|||
|
|
- **Methods**
|
|||
|
|
- `override bool Equals(object obj)`
|
|||
|
|
Compares `Begin` and `End` using `double.Equals()`.
|
|||
|
|
- `override int GetHashCode()`
|
|||
|
|
Returns `base.GetHashCode()`.
|
|||
|
|
|
|||
|
|
> **Note**: `IntervalSec` inherits from `Exceptional` (not shown in source), which likely provides exception-handling infrastructure.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Invariants
|
|||
|
|
|
|||
|
|
- **`Test.Id` and `Test.Description`**
|
|||
|
|
May be empty strings after default construction; no validation enforced.
|
|||
|
|
|
|||
|
|
- **`Test.Guid`**
|
|||
|
|
Defaults to `Guid.Empty`; no uniqueness guarantee is enforced by the class itself.
|
|||
|
|
|
|||
|
|
- **`Test.InceptionDate`**
|
|||
|
|
Always initialized to `DateTime.Now` in the default constructor.
|
|||
|
|
|
|||
|
|
- **`Test.Channels` ordering**
|
|||
|
|
Channels are sorted by:
|
|||
|
|
1. `AbsoluteDisplayOrder`
|
|||
|
|
2. `ParentModule.Number`
|
|||
|
|
3. `Channel.Number`
|
|||
|
|
...and *then* reordered by `ChannelOrder.txt` if present (via `ChannelOrderComparor`).
|
|||
|
|
**Critical**: If `ChannelOrder.txt` is missing or unreadable, only the first three criteria apply.
|
|||
|
|
|
|||
|
|
- **`DasTimestamp.NumberOfBitsPerSample`**
|
|||
|
|
Defaults to `64` (i.e., `8 * sizeof(ulong)`) if missing in XML during deserialization.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` behavior**
|
|||
|
|
Backs up `.dts` file only if no `.bak` exists *at the time of save*. Backup is deleted on successful save.
|
|||
|
|
|
|||
|
|
- **XML attribute extraction**
|
|||
|
|
Uses `AttributeExtractor<XmlSerializationTagAttribute>` to map property names to XML attribute names. Property names must match exactly (e.g., `"BaseSerialNumber"` → attribute `"BaseSerialNumber"`).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Dependencies
|
|||
|
|
|
|||
|
|
### Internal Dependencies (from source)
|
|||
|
|
- `DTS.Common.Utilities`
|
|||
|
|
- `DotNetProgrammingConstructs.Property<T>`: Used for property wrappers with metadata (e.g., `Property<double>`, `Property<string>`).
|
|||
|
|
- `Logging.APILogger`: Used for logging exceptions (e.g., in `TryGetChannelOrder`, `SaveTest`).
|
|||
|
|
- `Xml.AttributeExtractor<T>`: Used to extract `[XmlSerializationTag]` attributes for XML serialization.
|
|||
|
|
- `DTS.Common.Utilities.Xml`
|
|||
|
|
- `SliceRaw.File` and `SliceRaw.File.Exporter`: Used in `Test.SaveTest` for SLICEWare-compatible export.
|
|||
|
|
- `System.Xml.Serialization`
|
|||
|
|
- `IXmlSerializable` interface (implemented by `Test` and `DasTimestamp`).
|
|||
|
|
- `System.Collections.Generic`
|
|||
|
|
- `Dictionary<string, int>` for channel ordering (`_channelOrder`).
|
|||
|
|
- `List<T>` for `Modules`, `DasTimestamps`, and `Channels`.
|
|||
|
|
|
|||
|
|
### External Dependencies (inferred)
|
|||
|
|
- `ChannelOrder.txt`: Required for channel ordering (loaded at runtime via `TryGetChannelOrder()`).
|
|||
|
|
- `APILogger`: External logging utility (not defined in source; assumed to be a static logger).
|
|||
|
|
- `SliceRaw.File.Exporter.Write(...)`: External serialization utility for SLICEWare compatibility.
|
|||
|
|
|
|||
|
|
### Inferred Consumers
|
|||
|
|
- Any code that needs to serialize/deserialize test metadata (e.g., `Test.SaveTest`, XML readers/writers).
|
|||
|
|
- Code that needs channel ordering (e.g., `Test.Channels`).
|
|||
|
|
- Code that converts custom objects to/from `Test` via `IConvertable`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Gotchas
|
|||
|
|
|
|||
|
|
- **`IntervalSec` default constructor leaves `Begin`/`End` uninitialized**
|
|||
|
|
Though initialized to `0.0`, the comment warns this is "uninitialized". Callers must explicitly set values.
|
|||
|
|
|
|||
|
|
- **`DasTimestamp.WriteXml` omits `FileName` and `NumberOfBitsPerSample`**
|
|||
|
|
Only `BaseSerialNumber` and `NumberOfSamples` are written to XML. `NumberOfBitsPerSample` is *read* but not *written*. This asymmetry may cause data loss.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` overwrites `.dts` in-place**
|
|||
|
|
Appends XML metadata to the *existing* `.dts` file (after SLICEWare data). If the original file is corrupted or truncated, this may cause issues.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` uses UTF-16 for XML metadata**
|
|||
|
|
Hardcoded `Encoding.Unicode` (UTF-16) for appended XML. May conflict with SLICEWare’s expectations if it assumes ASCII/UTF-8.
|
|||
|
|
|
|||
|
|
- **`Test.Guid` and `Test.FaultFlags` use fallback defaults on deserialization**
|
|||
|
|
`Guid` defaults to `Guid.Empty` on parse failure; `FaultFlags` defaults to `0`. No error is raised.
|
|||
|
|
|
|||
|
|
- **`ExtendedFaultFlags1–4` are optional in XML**
|
|||
|
|
`GetUintSafe` returns `0` if attributes are missing or invalid. No warning is logged beyond `APILogger.Log` (non-fatal).
|
|||
|
|
|
|||
|
|
- **`IConvertable.FromDtsSerializationTest` passes `ReportErrors` but does not enforce error handling**
|
|||
|
|
The delegate is provided but not validated; callers may ignore errors.
|
|||
|
|
|
|||
|
|
- **`Test.Channels` sorting is order-dependent**
|
|||
|
|
`CompareChannels` is called first (for primary sort), *then* `ChannelOrderComparor` is applied. If `ChannelOrder.txt` is loaded, it overrides the primary sort order.
|
|||
|
|
|
|||
|
|
- **`TryGetChannelOrder` is not idempotent**
|
|||
|
|
`_channelOrder` is cleared on every call. If `ChannelOrder.txt` is modified during runtime, re-calling `TryGetChannelOrder()` is required to pick up changes.
|
|||
|
|
|
|||
|
|
- **`IntervalSec` rounding is applied only on `get`**
|
|||
|
|
`Begin`/`End` store raw values; rounding occurs only when accessed. This may cause `Begin != _Begin.Value` during serialization if `DoRoundOffValues` is `true`.
|
|||
|
|
|
|||
|
|
- **`Test.Equals` ignores `Guid`, `FaultFlags`, `Modules.Count`, and `DasTimestamps`**
|
|||
|
|
Only `Id`, `Description`, and `Modules` are compared. This is likely a bug or intentional simplification.
|
|||
|
|
|
|||
|
|
- **`Test.WriteXml` writes `Software`/`SoftwareVersion` as attributes, not elements**
|
|||
|
|
This is inconsistent with `Modules`/`DasTimestamps` (which are elements). Ensure consumers expect this.
|
|||
|
|
|
|||
|
|
- **`Test.ReadXml` uses `ReadSubtree()` for child deserialization**
|
|||
|
|
This isolates parsing but may fail if child `ReadXml` implementations do not consume all tokens in their subtree.
|
|||
|
|
|
|||
|
|
- **No validation for `IntervalSec.Begin >= End`**
|
|||
|
|
The class does not enforce that `Begin ≤ End`. Invalid intervals are allowed.
|
|||
|
|
|
|||
|
|
- **`Test` constructors do not initialize `Modules` or `DasTimestamps`**
|
|||
|
|
They are initialized via `Property<T>` defaults (empty lists), but the comment for `Test()` warns `Id`/`Description` are left empty. No other fields are explicitly initialized.
|
|||
|
|
|
|||
|
|
- **`DasTimestamp.ParentTest` is read-only**
|
|||
|
|
Set only in constructor; cannot be reassigned later.
|
|||
|
|
|
|||
|
|
- **`Test.InlineSerializedData` setter propagates to `Modules`**
|
|||
|
|
Modifying this property on `Test` updates all `Modules.InlineSerializedData`. This may cause unintended side effects if modules are shared or reused.
|
|||
|
|
|
|||
|
|
- **`GetUintSafe` swallows exceptions silently**
|
|||
|
|
Returns `defaultValue` on failure and logs via `APILogger`, but does not propagate errors.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` deletes backup on success**
|
|||
|
|
If `SaveTest` fails partway (e.g., after backup but before final save), the backup may be left orphaned.
|
|||
|
|
|
|||
|
|
- **`IntervalSec.NumberRoundingDecimalPlaces` uses a `Property<int>` wrapper**
|
|||
|
|
This adds indirection but no additional behavior. The underlying value is mutable and not validated.
|
|||
|
|
|
|||
|
|
- **`Test.Guid` is serialized as a string**
|
|||
|
|
Uses `Guid.ToString()` (default format: `"D"`), which is standard but should be confirmed for compatibility.
|
|||
|
|
|
|||
|
|
- **`Test.Channels` includes `CalculatedChannels`**
|
|||
|
|
These are appended to `Channels` alongside regular `Channels`. Ensure consumers distinguish them if needed.
|
|||
|
|
|
|||
|
|
- **`DasTimestamp` uses `CultureInfo("")` (invariant culture)**
|
|||
|
|
This is appropriate for numeric serialization but may cause issues if XML attributes use locale-specific formatting.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` appends metadata to `.dts` file**
|
|||
|
|
This assumes the `.dts` file is text-based and supports appending. Binary `.dts` files may be corrupted.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` uses `StringWriter` without specifying encoding**
|
|||
|
|
`StringWriter` defaults to UTF-16, but `fileWriter` uses `Encoding.Unicode` (also UTF-16). This is consistent but unusual.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not validate `testId` or `directory`**
|
|||
|
|
May throw `PathTooLongException`, `DirectoryNotFoundException`, or similar.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not flush or close streams explicitly**
|
|||
|
|
Relies on `using` blocks, but `StreamWriter` disposal may not guarantee immediate disk write.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not handle concurrent access**
|
|||
|
|
No locking or atomicity guarantees.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not validate XML output**
|
|||
|
|
Assumes `WriteXml` succeeds; no validation of XML well-formedness.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not handle `metaData` being malformed XML**
|
|||
|
|
Appends raw `metaData` string; if it is invalid XML, the file may be corrupted.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not handle `metaData` being null**
|
|||
|
|
`String.IsNullOrEmpty(metaData)` is not checked before appending.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not handle `metaData` being empty**
|
|||
|
|
Appends `writer.NewLine + writer` (empty) + `metaData` (empty), resulting in a blank line.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not handle `metaData` containing `</Test>` or `</TestSetup>`**
|
|||
|
|
May interfere with `GetMetaDataFromDTSFile` logic.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not handle `metaData` being larger than file buffer**
|
|||
|
|
May cause out-of-memory issues for very large metadata.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not handle `metaData` being encoded differently than UTF-16**
|
|||
|
|
Appending non-UTF-16 data may corrupt the file.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not handle `metaData` being truncated or incomplete**
|
|||
|
|
May leave the file in an inconsistent state.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not handle `metaData` being corrupted or malformed**
|
|||
|
|
May cause downstream parsing errors.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest` does not handle `metaData` being duplicated**
|
|||
|
|
May cause duplicate metadata sections.
|
|||
|
|
|
|||
|
|
- **`Test.SaveTest`
|