Skip to content

Local conformance test data harvested from reference implementations #36

Description

@andrew

The upstream package-url/vers-spec conformance suite is thin and uneven: 491 npm native-parse cases but 1 npm containment case, 977 maven comparison cases but 0 maven native-parse cases, 1 gem case total, and zero data for cargo, composer, cpan, dart/pub, deb, golang, hackage, hex, rpm, semver. Passing it doesn't prove much beyond "can parse the URI format".

Rather than wait on upstream, add a testdata/local/tests/ directory in the same JSON schema, run it through the existing conformance runner, and fill it by harvesting fixtures from each ecosystem's own reference implementation (node-semver, pypa/packaging, composer/semver, pub_semver, rubygems, dpkg, rpm, dtolnay/semver, maven-artifact). The harvested JSON is committed so go test needs nothing but Go.

Infrastructure

  • Change conformance_test.go to filepath.Glob("testdata/*/tests/*_<type>_test.json") instead of enumerating filenames, so both testdata/vers-spec/tests/ and testdata/local/tests/ are picked up and new upstream files run automatically after a submodule bump
  • Wire up vers_canonical_parse_test.json (currently exists upstream but isn't run)
  • Add testdata/local/skip.json mapping {filename: [{description, reason}]} for known intentional divergences, checked before each subtest with t.Skip(reason)

Seed local data from existing tests

  • testdata/local/tests/composer_range_from_native_test.json from composer_pub_test.go tables
  • testdata/local/tests/composer_version_cmp_test.json
  • testdata/local/tests/pub_range_from_native_test.json
  • testdata/local/tests/pub_version_cmp_test.json
  • Trim composer_pub_test.go down to error-path cases once the JSON covers the happy paths

Harvester

  • tools/harvest/main.go (invoked via go run ./tools/harvest, kept out of the library build) that shallow-clones reference repos, extracts assertion tables, and writes testdata/local/tests/*.json with source repo + commit SHA recorded in a top-level $comment field
  • Makefile target harvest that runs it

Harvest: comparison tests (upstream has zero for all of these)

  • npm from npm/node-semver/test/fixtures/{comparisons,equality}.js
  • pypi from pypa/packaging/tests/test_version.py
  • gem from rubygems/rubygems/test/rubygems/test_gem_version.rb
  • composer from composer/semver/tests/ComparatorTest.php
  • pub from dart-lang/tools/pkgs/pub_semver/test/version_test.dart
  • cargo/semver from dtolnay/semver/tests/
  • deb from dpkg/lib/dpkg/t/t-version.c
  • rpm from rpm-software-management/rpm/tests/rpmvercmp.at
  • go from golang.org/x/mod/semver test data

Harvest: native-range tests

  • npm containment from node-semver/test/fixtures/{range-include,range-exclude}.js (upstream has 1 case)
  • pypi from pypa/packaging/tests/test_specifiers.py (upstream has 3 cases)
  • gem from rubygems/test_gem_requirement.rb (upstream has 1 case)
  • composer from composer/semver/tests/VersionParserTest.php data providers
  • pub from pub_semver/test/version_range_test.dart and version_constraint_test.dart
  • cargo from dtolnay/semver/tests/test_version_req.rs
  • maven from maven-artifact VersionRangeTest.java (upstream has 0 native cases)

Harvest: generated containment tests

  • For each scheme, cross the harvested ranges against the harvested versions and shell out to the reference binary (npx semver, python -c 'import packaging.specifiers...', php -r, dart run, ruby -e 'Gem::Requirement...') to record the expected answer; skip a scheme with a warning if its runtime isn't on PATH

Follow-up

  • Input length / constraint-count bounds on Parse and ParseNative (the Ruby vers gem caps at 2048 chars / 64 constraints; this library currently has no bound)
  • Once testdata/local/ has meaningful coverage, open an upstream PR to package-url/vers-spec with the generated files and a link to the harvester; don't block on it landing

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions