Skip to content

Test unit definitions for wrong base units and ambiguous abbreviations - #1744

Open
tmilnthorp wants to merge 2 commits into
angularsen:masterfrom
tmilnthorp:tmilntho/unit-definition-tests
Open

tmilnthorp wants to merge 2 commits into
angularsen:masterfrom
tmilnthorp:tmilntho/unit-definition-tests

Conversation

@tmilnthorp

Copy link
Copy Markdown
Collaborator

The conversion tests check each unit against test values, but some mistakes in the unit definitions slip past them:

This adds UnitDefinitionsTests, which checks every quantity at runtime. The tests need no network, tools or secrets, so they run on every PR, including from forks.

Checks

  1. BaseUnits give the unit's conversion factor. The factor of a unit made of its BaseUnits (e.g. foot and second for FootPerSecond) must match its actual conversion. Units are compared with the quantity's unit made of SI base units, or with each other if there is none, because a quantity's base unit isn't always made of SI base units. The factors are computed exactly from the conversion expressions. Affine units compare the size of the degree, and logarithmic units are skipped.
  2. Abbreviations are unique within a quantity, in en-US and in each culture with a satellite resource assembly (currently ru-RU, zh-CN, fr-CA). The check uses UnitAbbreviationsCache, including its fallback to en-US, so it sees what parsing sees.
  3. Abbreviations use the micro sign (U+00B5), as generated prefixes do, not the Greek letter mu (U+03BC). The two look identical, but parsing treats them as different characters, so typing A/µs doesn't match A/μs.

Existing violations

The tests found these, which are listed as known with the reason for each, so the tests pass today and catch new mistakes:

  • 50 units with wrong BaseUnits (their conversions are correct):
    • Radioactivity: the curie and rutherford, and their prefixed units, are defined as 1 per second.
    • RadiationExposure: the roentgen is defined as 1 C/kg instead of 2.58e-4.
    • ElectricPotentialChangeRate: the units per minute, hour and microsecond, where time has exponent −4.
    • PressureChangeRate: the units per minute, and pound-force taken as pound.
    • HeatFlux: the units per square millimeter.
    • FluidResistance: three units.
    • Acceleration: knot per second and per minute.
    • AreaDensity.PoundPerThousandSquareFeet and VolumePerLength.LiterPerMeter.
  • 7 ambiguous abbreviations:
    • pt and pica (DTP and printer's point; UnitParserTests covers this case).
    • cwt (long and short hundredweight).
    • кгс (kilogram-force and kilopond, which are the same unit).
    • Three mistranslations:
      • zh-CN Hectare is 英亩, which means acre.
      • zh-CN NauticalMile is 纳米, which means nanometer.
      • ru-RU NauticalMile is мил, the same as Mil.
  • 4 definitions with the Greek mu, which become 18 units after prefixes: GraySquareMicrometer, AmperePerMicrosecond, VoltPerMicrosecond and GramPerMicroliter.

A fourth test fails when a listed violation no longer occurs, so fixing one also means removing it from its list, and the lists only shrink. I plan to fix these in follow-up PRs: the localizations and micro signs first, then the BaseUnits. The BaseUnits fixes change what GetUnitInfoFor(BaseUnits) and ToUnit(UnitSystem) return for those units.

Not covered

  • Units whose BaseUnits don't cover the quantity's dimensions, such as Tesla and StandardVolumeFlow. Their factors can't be compared. Fix Tesla BaseUnits to match MagneticField dimensions #1734 adds a test for that.
  • A wrong base unit in a quantity with no other unit to compare it with. For example, the base unit of SpecificFuelConsumption has BaseUnits meter and second, but no other unit of that quantity has BaseUnits.

Testing

  • All 260 new test cases pass on net10.0.
  • Removing an entry from a known list makes the test for that quantity fail with a clear message, for example: Radioactivity.Curie: BaseUnits T=Second give 1 Becquerel, but its conversion gives 3.7E+10 (compared to Becquerel).
  • So does adding an entry that isn't a violation, and changing Length.Foot's BaseUnits to inch in the JSON.
  • I couldn't run net48 locally. I avoided APIs missing on .NET Framework, and CI runs it.

🤖 Generated with Claude Code

https://claude.ai/code/session_012XKhDsyHDc5BHrmibxScqG

The conversion tests compare each unit against test values, but nothing
checks a unit's BaseUnits against its conversion, or that its
abbreviations can be parsed unambiguously. Add tests that check every
quantity:
- The factor implied by each unit's BaseUnits matches its conversion,
  relative to the quantity's other units.
- No two units of a quantity share an abbreviation in any culture.
- Abbreviations use the micro sign (U+00B5) like the generated prefixes,
  not the Greek letter mu (U+03BC), which parsing treats differently.

Existing violations are listed as known, with the reason for each, so
the tests catch new mistakes while those are fixed separately. Another
test fails when a known violation is fixed but still listed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XKhDsyHDc5BHrmibxScqG
@codecov

codecov Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98%. Comparing base (3bf1ef4) to head (84b5663).

Additional details and impacted files
@@          Coverage Diff           @@
##           master   #1744   +/-   ##
======================================
  Coverage      98%     98%           
======================================
  Files         515     515           
  Lines       24092   24092           
======================================
  Hits        23692   23692           
  Misses        400     400           
Flag Coverage Δ
net48 97% <ø> (+<1%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

On .NET Framework, the test runner can shadow copy UnitsNet.dll without
its satellite assemblies, so looking next to it found only en-US and the
abbreviation tests skipped the other cultures. Look in the test output
directory instead, and fail if a localized culture isn't found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XKhDsyHDc5BHrmibxScqG

This branch has not been deployed

No deployments
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.

1 participant