Skip to content

fix(json-cppagent): emit numeric Sample values as JSON numbers#143

Draft
ottobolyos wants to merge 17 commits intoTrakHound:masterfrom
ottobolyos:fix/issue-129
Draft

fix(json-cppagent): emit numeric Sample values as JSON numbers#143
ottobolyos wants to merge 17 commits intoTrakHound:masterfrom
ottobolyos:fix/issue-129

Conversation

@ottobolyos
Copy link
Copy Markdown

@ottobolyos ottobolyos commented Apr 25, 2026

Summary

Fixes #129 — numeric Sample values were emitted as JSON string tokens under the JSON-cppagent formatter, breaking parity with the cppagent reference implementation and the XSD FloatSampleValueType union (xs:float | "UNAVAILABLE").

  • Numeric Sample values serialize as JSON number tokens; the "UNAVAILABLE" sentinel still serializes as a string token.
  • A custom JsonConverter on the Sample-value object property branches on the runtime type: numeric primitives go through WriteNumberValue; the UNAVAILABLE sentinel and any non-numeric fallback go through WriteStringValue.
  • Replace double.IsFinite with a cross-TFM-portable finite-value check so the converter compiles on netstandard2.0 / net48.
  • Harden the Sample-value converter's edge-case handling for boxed numerics, infinities, and NaN.
  • New unit-test project MTConnect.NET-JSON-cppagent-Tests covers numeric, sentinel, edge-case, and three-space scenarios plus a guard that scans the cppagent library for unconditional WriteStringValue against Sample-value writers.
  • Wire-format end-to-end coverage for the IObservation to JSON path under the cppagent formatter.
  • No public API changes.

@ottobolyos ottobolyos force-pushed the fix/issue-129 branch 2 times, most recently from 3025b22 to ef14a82 Compare April 28, 2026 10:55
The docs/testing/issue-129/ subtree carried phase-by-phase campaign writeups that
referenced internal tooling (CONVENTIONS rule-book, internal section
numbers, extra-files.user/ paths, internal tracker terminology). Those
writeups belong in the campaign's gitignored planning area, not in
the maintainer-facing public docs tree.
Addresses follow-up findings on the JsonSampleValueConverter and the
JsonSampleValue carrier surfaced after the initial issue-129 fix:

- JsonSampleValueConverter: gate WriteNumberValue on double.IsFinite so
  NaN/Infinity round-trip as JSON string tokens instead of crashing the
  Utf8JsonWriter.
- JsonSampleValueConverter: empty/whitespace-only string values emit a
  JSON null token, keeping the wire shape consistent with "no value
  supplied".
- JsonSampleValueConverter: short-circuit on a space character before
  double.TryParse so ThreeSpaceSampleValueType payloads stay on the
  cheap path.
- JsonSampleValueConverter: replace string.Format fallback with
  Convert.ToString(value, InvariantCulture) so the contract is explicit
  for non-string non-numeric carriers.
- JsonSampleValueConverter.Read: throw JsonException on unsupported
  token kinds (boolean / array / object) so feed corruption is visible
  to callers instead of being silently dropped.
- JsonSampleValue.ToObservation: null-guard ResetTriggered and
  Statistic round-trips so omitting the JSON property no longer stamps
  the observation with a stray default-enum value (mirrors the
  JsonDataItem.ToDataItem path).
- SampleValueWireFormatE2ETests: re-word XML doc to drop references to
  internal planning conventions.

Tests:

- New JsonSampleValueConverterEdgeCaseTests covers each behavioral
  finding (non-finite numbers, empty/whitespace null, ThreeSpace short
  circuit, invariant-culture fallback, Read default-branch throw).
- New JsonSampleValueToObservationTests pins the null-guard behavior on
  the carrier's ToObservation path.
- New TestHelpers/RepoRootLocator extracts the bin-folder walk-up
  helper so source-surface guards share one implementation.
- SampleValueWriteStringValueGuardTests now consumes the shared
  RepoRootLocator instead of carrying its own copy of the helper.
- JsonSampleValueNumericTokenTests removes the "returns null for
  unsupported token" case (now covered by the throws-JsonException
  pin in JsonSampleValueConverterEdgeCaseTests).
`double.IsFinite` is a .NET Core 2.1 / .NET 5+ / netstandard 2.1 API.
MTConnect.NET-JSON-cppagent multi-targets net47 / net48 / netstandard2.0
in Release where the method does not exist; the Release build failed
with CS0117 ('double' does not contain a definition for 'IsFinite')
and CS0165 (the cascading 'parsed' unassigned-local error).

Replace with the equivalent guard `!double.IsNaN(parsed) &&
!double.IsInfinity(parsed)` which is available on every supported TFM.
The behaviour is identical: both reject NaN, +Infinity, and -Infinity
and accept every finite double.

Surfaced via `dotnet pack -c Release` from the integration branch.
The five section headers in JsonSampleValueConverterEdgeCaseTests carried
internal audit-finding codes; rewrite each header so the comment is a
self-contained one-line description of the contract being pinned. Also
remove the same code reference from the trailing note in
JsonSampleValueNumericTokenTests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JSON-cppagent-mqtt: numeric Sample value emitted as JSON string instead of number token

1 participant