Skip to content

Conversation

@petergardfjall
Copy link
Collaborator

This PR is an attempt to make the code honor the spec rules on producing a canonical purl when a PackageURL is turned into its string representation (ToString() and String()).


The old test suite (test-suite-data.json) is no longer present upstream. For now I updated the Makefile to run against the last commit where test-suite-data.json was still present in the repo (it was removed in 8a699a).

This should be removed as soon as we can migrate to the new test suite (see separate PR).

It fails on the following tests:

  • Two tests with invalid subpaths: we fail to parse these, which used to be correct before all of a sudden is_invalid for these cases was swapped from true to false in this commit without much of an explanation. These test cases appear to have been removed from the new test set though.

For the new test suite (a pull request to make use of it is up here) it currently fails on 45 and passes on 468 test cases. For the failed ones:

  • For two test cases for pkg:conan I cannot figure out why we are failing. I've opened a ticket since I suspect that the test cases might be incorrect purl-spec#643.
  • Of the remaining errors almost all are ones where the expected output in the test case is not a canonical purl/does not follow purl encoding guidelines. I've opened purl-spec#644 to better understand what's expected from library implementations.

Makefile Outdated

test:
curl -Ls https://raw.githubusercontent.com/package-url/purl-spec/master/test-suite-data.json -o testdata/test-suite-data.json
curl -Ls https://raw.githubusercontent.com/package-url/purl-spec/de752b1160c7dc309482aaa80fd31884005aaec5/test-suite-data.json -o testdata/test-suite-data.json
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be entirely replaced if/when #80 is merged.

@coveralls
Copy link

Pull Request Test Coverage Report for Build 17266694404

Details

  • 35 of 36 (97.22%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+3.6%) to 85.761%

Changes Missing Coverage Covered Lines Changed/Added Lines %
packageurl.go 35 36 97.22%
Totals Coverage Status
Change from base Build 13610888770: 3.6%
Covered Lines: 265
Relevant Lines: 309

💛 - Coveralls

for _, qq := range q {
v.Add(qq.Key, qq.Value)
}
return v.Encode()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot use Values.Encode() since it uses https://pkg.go.dev/net/url#QueryEscape under the hood to encode the value. This works in many cases but has caveats (does not work according to spec for whitespace and colon :).

u := &url.URL{
Scheme: "pkg",
RawQuery: p.Qualifiers.urlQuery(),
Fragment: p.Subpath,
Copy link
Collaborator Author

@petergardfjall petergardfjall Aug 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: we cannot use url.Fragment since url.String will call u.EscapedFragment() and we end up with an incorrect escaping (similar to url.QueryEscape I believe).

Instead we "manually" add any fragment part at the end.

packageurl.go Outdated
Comment on lines 661 to 668
qualifierKeys := slices.Collect(maps.Keys(p.Qualifiers.Map()))
hasNamespace := p.Namespace != ""
hasChannel := slices.Contains(qualifierKeys, "channel")
if hasNamespace && !hasChannel {
return errors.New("channel qualifier is required if namespace is present")
}
if hasChannel && !hasNamespace {
return errors.New("namespace is required if channel qualifier is present")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An attempt to make the code more readable.

import "testing"

// Verifies that qualifier values are properly percent-encoded.
func TestQualifierValueEncoding(t *testing.T) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some explicit testing of qualifier encoding (outside of purl-spec test suite) since this was a problematic spot which had poor coverage in the upstream tests.

@petergardfjall
Copy link
Collaborator Author

@shibumi @mcombuechen ?
Would anyone care to have a look?

@petergardfjall
Copy link
Collaborator Author

Barring some outstanding issues with the purl spec test suite (see below) this code now passes the entire purl-spec suite. We should first merge #80 which changes the code to run against the new test suite in the purl-spec repo. When that is merged we can merge this PR.

Until these issues/PRs are fixed the code in this PR will fail to complete the entire test suite (it will fail on about 10 out of 500).


test:
curl -Ls https://raw.githubusercontent.com/package-url/purl-spec/master/test-suite-data.json -o testdata/test-suite-data.json
go test -v -cover ./...
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: relies on #80 being merged.

func validCustomRules(p PackageURL) error {
q := p.Qualifiers.Map()
switch p.Type {
case TypeConan:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conan spec has been relaxed.

return errors.New("channel qualifier does not exist")
}
} else {
if val, ok := q["channel"]; ok {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conan spec has been relaxed.

if p.Version == "" {
return errors.New("version is required")
}
case TypeCran:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -1,572 +0,0 @@
/*
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file should be replaced with packageurl_test.go from #80

@petergardfjall
Copy link
Collaborator Author

Anyone up for reviewing?

@petergardfjall
Copy link
Collaborator Author

petergardfjall commented Nov 24, 2025

Anyone up for reviewing?

Bump

shibumi
shibumi previously approved these changes Nov 24, 2025
@shibumi
Copy link
Collaborator

shibumi commented Nov 24, 2025

Your PR relies on: #80 and there we still see failing tests. :/
Do you mind incorporating that PR into yours and fixing it? Or do you want to merge it without #80?

@petergardfjall
Copy link
Collaborator Author

petergardfjall commented Dec 3, 2025

Your PR relies on: #80 and there we still see failing tests. :/ Do you mind incorporating that PR into yours and fixing it? Or do you want to merge it without #80?

Thanks @shibumi for taking the time to review.
I rebased this PR onto #80 and reran the tests. Now there are only a dozen or so failing tests (see below).
However, all of those failing test cases are incorrect.

In fact I have opened PRs in the purl-spec to fix most of them:

There is also this PR which fixes the bazel-test cases.

$ make test | grep '\-\-\- FAIL:'
--- FAIL: TestPurlSpecFixtures (0.02s)
    --- FAIL: TestPurlSpecFixtures/bazel-test.json[1]roundtrip (0.00s)
    --- FAIL: TestPurlSpecFixtures/bazel-test.json[2]parse (0.00s)
    --- FAIL: TestPurlSpecFixtures/bazel-test.json[4]roundtrip (0.00s)
    --- FAIL: TestPurlSpecFixtures/bazel-test.json[5]parse (0.00s)
    --- FAIL: TestPurlSpecFixtures/bazel-test.json[6]build (0.00s)
    --- FAIL: TestPurlSpecFixtures/conan-test.json[9]parse (0.00s)
    --- FAIL: TestPurlSpecFixtures/conan-test.json[10]parse (0.00s)
    --- FAIL: TestPurlSpecFixtures/conan-test.json[11]build (0.00s)
    --- FAIL: TestPurlSpecFixtures/conan-test.json[12]parse (0.00s)
    --- FAIL: TestPurlSpecFixtures/conan-test.json[13]parse (0.00s)
    --- FAIL: TestPurlSpecFixtures/conan-test.json[14]build (0.00s)
    --- FAIL: TestPurlSpecFixtures/cran-test.json[8]parse (0.00s)
    --- FAIL: TestPurlSpecFixtures/cran-test.json[9]parse (0.00s)
    --- FAIL: TestPurlSpecFixtures/cran-test.json[10]build (0.00s)
make: *** [Makefile:6: test] Error 1

With those PRs applied the tests run cleanly. 🎉

git submodule update --init
git submodule update --remote
go test -v -cover ./...
=== RUN   TestQualifierValueEncoding
=== RUN   TestQualifierValueEncoding/must_percent-encode_a_qualifier_value
=== RUN   TestQualifierValueEncoding/must_not_percent-encode_colons_in_qualifier_values
=== RUN   TestQualifierValueEncoding/must_properly_percent-encode_a_plus
=== RUN   TestQualifierValueEncoding/must_order_qualifier_values_lexicographically_by_key
=== RUN   TestQualifierValueEncoding/must_percent-encode_separators_in_qualifier_value
=== RUN   TestQualifierValueEncoding/must_escape_a_qualifier_value
--- PASS: TestQualifierValueEncoding (0.00s)
    --- PASS: TestQualifierValueEncoding/must_percent-encode_a_qualifier_value (0.00s)
    --- PASS: TestQualifierValueEncoding/must_not_percent-encode_colons_in_qualifier_values (0.00s)
    --- PASS: TestQualifierValueEncoding/must_properly_percent-encode_a_plus (0.00s)
    --- PASS: TestQualifierValueEncoding/must_order_qualifier_values_lexicographically_by_key (0.00s)
    --- PASS: TestQualifierValueEncoding/must_percent-encode_separators_in_qualifier_value (0.00s)
    --- PASS: TestQualifierValueEncoding/must_escape_a_qualifier_value (0.00s)
=== RUN   TestPercentEncode
=== RUN   TestPercentEncode/must_not_percent-encode_alphanumeric_characters
=== RUN   TestPercentEncode/must_not_percent-encode_punctuation_characters
=== RUN   TestPercentEncode/must_not_percent-encode_colon
=== RUN   TestPercentEncode/must_percent-encode_separator_characters_other_than_colon
=== RUN   TestPercentEncode/must_percent-encode_a_plus
=== RUN   TestPercentEncode/must_percent-encode_a_whitespace
--- PASS: TestPercentEncode (0.00s)
    --- PASS: TestPercentEncode/must_not_percent-encode_alphanumeric_characters (0.00s)
    --- PASS: TestPercentEncode/must_not_percent-encode_punctuation_characters (0.00s)
    --- PASS: TestPercentEncode/must_not_percent-encode_colon (0.00s)
    --- PASS: TestPercentEncode/must_percent-encode_separator_characters_other_than_colon (0.00s)
    --- PASS: TestPercentEncode/must_percent-encode_a_plus (0.00s)
    --- PASS: TestPercentEncode/must_percent-encode_a_whitespace (0.00s)
=== RUN   TestPurlSpecFixtures
=== RUN   TestPurlSpecFixtures/alpm-test.json[1]parse
=== RUN   TestPurlSpecFixtures/alpm-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/alpm-test.json[3]build
=== RUN   TestPurlSpecFixtures/alpm-test.json[4]parse
=== RUN   TestPurlSpecFixtures/alpm-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/alpm-test.json[6]build
=== RUN   TestPurlSpecFixtures/alpm-test.json[7]parse
=== RUN   TestPurlSpecFixtures/alpm-test.json[8]roundtrip
=== RUN   TestPurlSpecFixtures/alpm-test.json[9]build
=== RUN   TestPurlSpecFixtures/apk-test.json[1]parse
=== RUN   TestPurlSpecFixtures/apk-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/apk-test.json[3]build
=== RUN   TestPurlSpecFixtures/apk-test.json[4]parse
=== RUN   TestPurlSpecFixtures/apk-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/apk-test.json[6]build
=== RUN   TestPurlSpecFixtures/bazel-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/bazel-test.json[2]parse
=== RUN   TestPurlSpecFixtures/bazel-test.json[3]build
=== RUN   TestPurlSpecFixtures/bazel-test.json[4]roundtrip
=== RUN   TestPurlSpecFixtures/bazel-test.json[5]parse
=== RUN   TestPurlSpecFixtures/bazel-test.json[6]build
=== RUN   TestPurlSpecFixtures/bazel-test.json[7]roundtrip
=== RUN   TestPurlSpecFixtures/bazel-test.json[8]parse
=== RUN   TestPurlSpecFixtures/bazel-test.json[9]build
=== RUN   TestPurlSpecFixtures/bazel-test.json[10]roundtrip
=== RUN   TestPurlSpecFixtures/bazel-test.json[11]parse
=== RUN   TestPurlSpecFixtures/bazel-test.json[12]build
=== RUN   TestPurlSpecFixtures/bazel-test.json[13]roundtrip
=== RUN   TestPurlSpecFixtures/bazel-test.json[14]parse
=== RUN   TestPurlSpecFixtures/bazel-test.json[15]build
=== RUN   TestPurlSpecFixtures/bazel-test.json[16]roundtrip
=== RUN   TestPurlSpecFixtures/bazel-test.json[17]parse
=== RUN   TestPurlSpecFixtures/bazel-test.json[18]build
=== RUN   TestPurlSpecFixtures/bazel-test.json[19]roundtrip
=== RUN   TestPurlSpecFixtures/bazel-test.json[20]parse
=== RUN   TestPurlSpecFixtures/bazel-test.json[21]build
=== RUN   TestPurlSpecFixtures/bitbucket-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/bitbucket-test.json[2]parse
=== RUN   TestPurlSpecFixtures/bitbucket-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/bitbucket-test.json[4]build
=== RUN   TestPurlSpecFixtures/bitbucket-test.json[5]parse
=== RUN   TestPurlSpecFixtures/bitbucket-test.json[6]roundtrip
=== RUN   TestPurlSpecFixtures/bitbucket-test.json[7]build
=== RUN   TestPurlSpecFixtures/bitnami-test.json[1]parse
=== RUN   TestPurlSpecFixtures/bitnami-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/bitnami-test.json[3]build
=== RUN   TestPurlSpecFixtures/bitnami-test.json[4]parse
=== RUN   TestPurlSpecFixtures/bitnami-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/bitnami-test.json[6]build
=== RUN   TestPurlSpecFixtures/bitnami-test.json[7]parse
=== RUN   TestPurlSpecFixtures/bitnami-test.json[8]roundtrip
=== RUN   TestPurlSpecFixtures/bitnami-test.json[9]build
=== RUN   TestPurlSpecFixtures/bitnami-test.json[10]parse
=== RUN   TestPurlSpecFixtures/bitnami-test.json[11]roundtrip
=== RUN   TestPurlSpecFixtures/bitnami-test.json[12]build
=== RUN   TestPurlSpecFixtures/cargo-test.json[1]parse
=== RUN   TestPurlSpecFixtures/cargo-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/cargo-test.json[3]build
=== RUN   TestPurlSpecFixtures/cargo-test.json[4]parse
=== RUN   TestPurlSpecFixtures/cargo-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/cargo-test.json[6]build
=== RUN   TestPurlSpecFixtures/cargo-test.json[7]parse
=== RUN   TestPurlSpecFixtures/cargo-test.json[8]roundtrip
=== RUN   TestPurlSpecFixtures/cargo-test.json[9]build
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[1]parse
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[3]build
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[4]parse
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[6]build
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[7]parse
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[8]roundtrip
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[9]build
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[10]parse
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[11]roundtrip
=== RUN   TestPurlSpecFixtures/cocoapods-test.json[12]build
=== RUN   TestPurlSpecFixtures/composer-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/composer-test.json[2]parse
=== RUN   TestPurlSpecFixtures/composer-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/composer-test.json[4]parse
=== RUN   TestPurlSpecFixtures/composer-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/composer-test.json[6]build
=== RUN   TestPurlSpecFixtures/composer-test.json[7]parse
=== RUN   TestPurlSpecFixtures/composer-test.json[8]roundtrip
=== RUN   TestPurlSpecFixtures/composer-test.json[9]build
=== RUN   TestPurlSpecFixtures/conan-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/conan-test.json[2]parse
=== RUN   TestPurlSpecFixtures/conan-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/conan-test.json[4]build
=== RUN   TestPurlSpecFixtures/conan-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/conan-test.json[6]parse
=== RUN   TestPurlSpecFixtures/conan-test.json[7]roundtrip
=== RUN   TestPurlSpecFixtures/conan-test.json[8]build
=== RUN   TestPurlSpecFixtures/conan-test.json[9]parse
=== RUN   TestPurlSpecFixtures/conan-test.json[10]roundtrip
=== RUN   TestPurlSpecFixtures/conan-test.json[11]build
=== RUN   TestPurlSpecFixtures/conan-test.json[12]parse
=== RUN   TestPurlSpecFixtures/conan-test.json[13]roundtrip
=== RUN   TestPurlSpecFixtures/conan-test.json[14]build
=== RUN   TestPurlSpecFixtures/conan-test.json[15]parse
=== RUN   TestPurlSpecFixtures/conan-test.json[16]roundtrip
=== RUN   TestPurlSpecFixtures/conan-test.json[17]build
=== RUN   TestPurlSpecFixtures/conda-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/conda-test.json[2]parse
=== RUN   TestPurlSpecFixtures/conda-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/conda-test.json[4]build
=== RUN   TestPurlSpecFixtures/conda-test.json[5]parse
=== RUN   TestPurlSpecFixtures/conda-test.json[6]roundtrip
=== RUN   TestPurlSpecFixtures/conda-test.json[7]build
=== RUN   TestPurlSpecFixtures/cpan-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/cpan-test.json[2]parse
=== RUN   TestPurlSpecFixtures/cpan-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/cpan-test.json[4]build
=== RUN   TestPurlSpecFixtures/cpan-test.json[5]build
=== RUN   TestPurlSpecFixtures/cpan-test.json[6]parse
=== RUN   TestPurlSpecFixtures/cpan-test.json[7]parse
=== RUN   TestPurlSpecFixtures/cpan-test.json[8]build
=== RUN   TestPurlSpecFixtures/cpan-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/cpan-test.json[10]build
=== RUN   TestPurlSpecFixtures/cpan-test.json[11]parse
=== RUN   TestPurlSpecFixtures/cpan-test.json[12]roundtrip
=== RUN   TestPurlSpecFixtures/cpan-test.json[13]build
=== RUN   TestPurlSpecFixtures/cpan-test.json[14]parse
=== RUN   TestPurlSpecFixtures/cpan-test.json[15]roundtrip
=== RUN   TestPurlSpecFixtures/cpan-test.json[16]build
=== RUN   TestPurlSpecFixtures/cpan-test.json[17]roundtrip
=== RUN   TestPurlSpecFixtures/cpan-test.json[18]parse
=== RUN   TestPurlSpecFixtures/cpan-test.json[19]build
=== RUN   TestPurlSpecFixtures/cran-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/cran-test.json[2]parse
=== RUN   TestPurlSpecFixtures/cran-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/cran-test.json[4]build
=== RUN   TestPurlSpecFixtures/cran-test.json[5]parse
=== RUN   TestPurlSpecFixtures/cran-test.json[6]parse
=== RUN   TestPurlSpecFixtures/cran-test.json[7]build
=== RUN   TestPurlSpecFixtures/cran-test.json[8]parse
=== RUN   TestPurlSpecFixtures/cran-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/cran-test.json[10]build
=== RUN   TestPurlSpecFixtures/cran-test.json[11]parse
=== RUN   TestPurlSpecFixtures/cran-test.json[12]roundtrip
=== RUN   TestPurlSpecFixtures/cran-test.json[13]build
=== RUN   TestPurlSpecFixtures/cran-test.json[14]parse
=== RUN   TestPurlSpecFixtures/cran-test.json[15]roundtrip
=== RUN   TestPurlSpecFixtures/cran-test.json[16]build
=== RUN   TestPurlSpecFixtures/deb-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/deb-test.json[2]parse
=== RUN   TestPurlSpecFixtures/deb-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/deb-test.json[4]build
=== RUN   TestPurlSpecFixtures/deb-test.json[5]parse
=== RUN   TestPurlSpecFixtures/deb-test.json[6]roundtrip
=== RUN   TestPurlSpecFixtures/deb-test.json[7]build
=== RUN   TestPurlSpecFixtures/deb-test.json[8]parse
=== RUN   TestPurlSpecFixtures/deb-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/deb-test.json[10]build
=== RUN   TestPurlSpecFixtures/deb-test.json[11]parse
=== RUN   TestPurlSpecFixtures/deb-test.json[12]roundtrip
=== RUN   TestPurlSpecFixtures/deb-test.json[13]build
=== RUN   TestPurlSpecFixtures/deb-test.json[14]parse
=== RUN   TestPurlSpecFixtures/deb-test.json[15]roundtrip
=== RUN   TestPurlSpecFixtures/deb-test.json[16]build
=== RUN   TestPurlSpecFixtures/deb-test.json[17]parse
=== RUN   TestPurlSpecFixtures/deb-test.json[18]roundtrip
=== RUN   TestPurlSpecFixtures/deb-test.json[19]build
=== RUN   TestPurlSpecFixtures/docker-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/docker-test.json[2]parse
=== RUN   TestPurlSpecFixtures/docker-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/docker-test.json[4]build
=== RUN   TestPurlSpecFixtures/docker-test.json[5]parse
=== RUN   TestPurlSpecFixtures/docker-test.json[6]roundtrip
=== RUN   TestPurlSpecFixtures/docker-test.json[7]build
=== RUN   TestPurlSpecFixtures/docker-test.json[8]parse
=== RUN   TestPurlSpecFixtures/docker-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/docker-test.json[10]build
=== RUN   TestPurlSpecFixtures/docker-test.json[11]parse
=== RUN   TestPurlSpecFixtures/docker-test.json[12]roundtrip
=== RUN   TestPurlSpecFixtures/docker-test.json[13]build
=== RUN   TestPurlSpecFixtures/gem-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/gem-test.json[2]parse
=== RUN   TestPurlSpecFixtures/gem-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/gem-test.json[4]build
=== RUN   TestPurlSpecFixtures/gem-test.json[5]parse
=== RUN   TestPurlSpecFixtures/gem-test.json[6]roundtrip
=== RUN   TestPurlSpecFixtures/gem-test.json[7]build
=== RUN   TestPurlSpecFixtures/gem-test.json[8]parse
=== RUN   TestPurlSpecFixtures/gem-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/gem-test.json[10]build
=== RUN   TestPurlSpecFixtures/generic-test.json[1]parse
=== RUN   TestPurlSpecFixtures/generic-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/generic-test.json[3]build
=== RUN   TestPurlSpecFixtures/generic-test.json[4]parse
=== RUN   TestPurlSpecFixtures/generic-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/generic-test.json[6]build
=== RUN   TestPurlSpecFixtures/generic-test.json[7]parse
=== RUN   TestPurlSpecFixtures/generic-test.json[8]roundtrip
=== RUN   TestPurlSpecFixtures/generic-test.json[9]build
=== RUN   TestPurlSpecFixtures/github-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/github-test.json[2]parse
=== RUN   TestPurlSpecFixtures/github-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/github-test.json[4]build
=== RUN   TestPurlSpecFixtures/github-test.json[5]parse
=== RUN   TestPurlSpecFixtures/github-test.json[6]roundtrip
=== RUN   TestPurlSpecFixtures/github-test.json[7]build
=== RUN   TestPurlSpecFixtures/github-test.json[8]parse
=== RUN   TestPurlSpecFixtures/github-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/github-test.json[10]build
=== RUN   TestPurlSpecFixtures/golang-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/golang-test.json[2]parse
=== RUN   TestPurlSpecFixtures/golang-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/golang-test.json[4]build
=== RUN   TestPurlSpecFixtures/golang-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/golang-test.json[6]parse
=== RUN   TestPurlSpecFixtures/golang-test.json[7]roundtrip
=== RUN   TestPurlSpecFixtures/golang-test.json[8]build
=== RUN   TestPurlSpecFixtures/golang-test.json[9]parse
=== RUN   TestPurlSpecFixtures/golang-test.json[10]roundtrip
=== RUN   TestPurlSpecFixtures/golang-test.json[11]build
=== RUN   TestPurlSpecFixtures/golang-test.json[12]parse
=== RUN   TestPurlSpecFixtures/golang-test.json[13]roundtrip
=== RUN   TestPurlSpecFixtures/golang-test.json[14]build
=== RUN   TestPurlSpecFixtures/golang-test.json[15]parse
=== RUN   TestPurlSpecFixtures/golang-test.json[16]roundtrip
=== RUN   TestPurlSpecFixtures/golang-test.json[17]build
=== RUN   TestPurlSpecFixtures/hackage-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/hackage-test.json[2]parse
=== RUN   TestPurlSpecFixtures/hackage-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/hackage-test.json[4]build
=== RUN   TestPurlSpecFixtures/hackage-test.json[5]parse
=== RUN   TestPurlSpecFixtures/hackage-test.json[6]parse
=== RUN   TestPurlSpecFixtures/hackage-test.json[7]build
=== RUN   TestPurlSpecFixtures/hackage-test.json[8]parse
=== RUN   TestPurlSpecFixtures/hackage-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/hackage-test.json[10]build
=== RUN   TestPurlSpecFixtures/hackage-test.json[11]parse
=== RUN   TestPurlSpecFixtures/hackage-test.json[12]roundtrip
=== RUN   TestPurlSpecFixtures/hackage-test.json[13]build
=== RUN   TestPurlSpecFixtures/hackage-test.json[14]parse
=== RUN   TestPurlSpecFixtures/hackage-test.json[15]roundtrip
=== RUN   TestPurlSpecFixtures/hackage-test.json[16]build
=== RUN   TestPurlSpecFixtures/hex-test.json[1]parse
=== RUN   TestPurlSpecFixtures/hex-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/hex-test.json[3]build
=== RUN   TestPurlSpecFixtures/hex-test.json[4]parse
=== RUN   TestPurlSpecFixtures/hex-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/hex-test.json[6]build
=== RUN   TestPurlSpecFixtures/hex-test.json[7]parse
=== RUN   TestPurlSpecFixtures/hex-test.json[8]roundtrip
=== RUN   TestPurlSpecFixtures/hex-test.json[9]build
=== RUN   TestPurlSpecFixtures/hex-test.json[10]parse
=== RUN   TestPurlSpecFixtures/hex-test.json[11]roundtrip
=== RUN   TestPurlSpecFixtures/hex-test.json[12]build
=== RUN   TestPurlSpecFixtures/huggingface-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/huggingface-test.json[2]parse
=== RUN   TestPurlSpecFixtures/huggingface-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/huggingface-test.json[4]build
=== RUN   TestPurlSpecFixtures/huggingface-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/huggingface-test.json[6]parse
=== RUN   TestPurlSpecFixtures/huggingface-test.json[7]roundtrip
=== RUN   TestPurlSpecFixtures/huggingface-test.json[8]build
=== RUN   TestPurlSpecFixtures/huggingface-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/huggingface-test.json[10]parse
=== RUN   TestPurlSpecFixtures/huggingface-test.json[11]roundtrip
=== RUN   TestPurlSpecFixtures/huggingface-test.json[12]build
=== RUN   TestPurlSpecFixtures/huggingface-test.json[13]parse
=== RUN   TestPurlSpecFixtures/huggingface-test.json[14]roundtrip
=== RUN   TestPurlSpecFixtures/huggingface-test.json[15]build
=== RUN   TestPurlSpecFixtures/huggingface-test.json[16]parse
=== RUN   TestPurlSpecFixtures/huggingface-test.json[17]roundtrip
=== RUN   TestPurlSpecFixtures/huggingface-test.json[18]build
=== RUN   TestPurlSpecFixtures/julia-test.json[1]parse
=== RUN   TestPurlSpecFixtures/julia-test.json[2]parse
=== RUN   TestPurlSpecFixtures/julia-test.json[3]parse
=== RUN   TestPurlSpecFixtures/julia-test.json[4]parse
=== RUN   TestPurlSpecFixtures/julia-test.json[5]build
=== RUN   TestPurlSpecFixtures/julia-test.json[6]build
=== RUN   TestPurlSpecFixtures/julia-test.json[7]roundtrip
=== RUN   TestPurlSpecFixtures/julia-test.json[8]roundtrip
=== RUN   TestPurlSpecFixtures/julia-test.json[9]parse
=== RUN   TestPurlSpecFixtures/julia-test.json[10]parse
=== RUN   TestPurlSpecFixtures/julia-test.json[11]build
=== RUN   TestPurlSpecFixtures/julia-test.json[12]build
=== RUN   TestPurlSpecFixtures/julia-test.json[13]parse
=== RUN   TestPurlSpecFixtures/luarocks-test.json[1]parse
=== RUN   TestPurlSpecFixtures/luarocks-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/luarocks-test.json[3]build
=== RUN   TestPurlSpecFixtures/luarocks-test.json[4]parse
=== RUN   TestPurlSpecFixtures/luarocks-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/luarocks-test.json[6]build
=== RUN   TestPurlSpecFixtures/luarocks-test.json[7]parse
=== RUN   TestPurlSpecFixtures/luarocks-test.json[8]roundtrip
=== RUN   TestPurlSpecFixtures/luarocks-test.json[9]build
=== RUN   TestPurlSpecFixtures/maven-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[2]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[4]build
=== RUN   TestPurlSpecFixtures/maven-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[6]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[7]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[8]build
=== RUN   TestPurlSpecFixtures/maven-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[10]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[11]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[12]build
=== RUN   TestPurlSpecFixtures/maven-test.json[13]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[14]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[15]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[16]build
=== RUN   TestPurlSpecFixtures/maven-test.json[17]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[18]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[19]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[20]build
=== RUN   TestPurlSpecFixtures/maven-test.json[21]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[22]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[23]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[24]build
=== RUN   TestPurlSpecFixtures/maven-test.json[25]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[26]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[27]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[28]build
=== RUN   TestPurlSpecFixtures/maven-test.json[29]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[30]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[31]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[32]build
=== RUN   TestPurlSpecFixtures/maven-test.json[33]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[34]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[35]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[36]build
=== RUN   TestPurlSpecFixtures/maven-test.json[37]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[38]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[39]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[40]build
=== RUN   TestPurlSpecFixtures/maven-test.json[41]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[42]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[43]build
=== RUN   TestPurlSpecFixtures/maven-test.json[44]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[45]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[46]build
=== RUN   TestPurlSpecFixtures/maven-test.json[47]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[48]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[49]build
=== RUN   TestPurlSpecFixtures/maven-test.json[50]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[51]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[52]build
=== RUN   TestPurlSpecFixtures/maven-test.json[53]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[54]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[55]build
=== RUN   TestPurlSpecFixtures/maven-test.json[56]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[57]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[58]build
=== RUN   TestPurlSpecFixtures/maven-test.json[59]parse
=== RUN   TestPurlSpecFixtures/maven-test.json[60]roundtrip
=== RUN   TestPurlSpecFixtures/maven-test.json[61]build
=== RUN   TestPurlSpecFixtures/mlflow-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/mlflow-test.json[2]parse
=== RUN   TestPurlSpecFixtures/mlflow-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/mlflow-test.json[4]build
=== RUN   TestPurlSpecFixtures/mlflow-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/mlflow-test.json[6]parse
=== RUN   TestPurlSpecFixtures/mlflow-test.json[7]roundtrip
=== RUN   TestPurlSpecFixtures/mlflow-test.json[8]build
=== RUN   TestPurlSpecFixtures/mlflow-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/mlflow-test.json[10]parse
=== RUN   TestPurlSpecFixtures/mlflow-test.json[11]roundtrip
=== RUN   TestPurlSpecFixtures/mlflow-test.json[12]build
=== RUN   TestPurlSpecFixtures/mlflow-test.json[13]parse
=== RUN   TestPurlSpecFixtures/mlflow-test.json[14]roundtrip
=== RUN   TestPurlSpecFixtures/mlflow-test.json[15]build
=== RUN   TestPurlSpecFixtures/mlflow-test.json[16]parse
=== RUN   TestPurlSpecFixtures/mlflow-test.json[17]roundtrip
=== RUN   TestPurlSpecFixtures/mlflow-test.json[18]build
=== RUN   TestPurlSpecFixtures/npm-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/npm-test.json[2]parse
=== RUN   TestPurlSpecFixtures/npm-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/npm-test.json[4]build
=== RUN   TestPurlSpecFixtures/npm-test.json[5]parse
=== RUN   TestPurlSpecFixtures/npm-test.json[6]roundtrip
=== RUN   TestPurlSpecFixtures/npm-test.json[7]build
=== RUN   TestPurlSpecFixtures/npm-test.json[8]parse
=== RUN   TestPurlSpecFixtures/npm-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/npm-test.json[10]build
=== RUN   TestPurlSpecFixtures/npm-test.json[11]parse
=== RUN   TestPurlSpecFixtures/npm-test.json[12]roundtrip
=== RUN   TestPurlSpecFixtures/npm-test.json[13]build
=== RUN   TestPurlSpecFixtures/npm-test.json[14]roundtrip
=== RUN   TestPurlSpecFixtures/npm-test.json[15]parse
=== RUN   TestPurlSpecFixtures/npm-test.json[16]parse
=== RUN   TestPurlSpecFixtures/npm-test.json[17]roundtrip
=== RUN   TestPurlSpecFixtures/nuget-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/nuget-test.json[2]parse
=== RUN   TestPurlSpecFixtures/nuget-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/nuget-test.json[4]build
=== RUN   TestPurlSpecFixtures/nuget-test.json[5]parse
=== RUN   TestPurlSpecFixtures/nuget-test.json[6]roundtrip
=== RUN   TestPurlSpecFixtures/nuget-test.json[7]build
=== RUN   TestPurlSpecFixtures/oci-test.json[1]parse
=== RUN   TestPurlSpecFixtures/oci-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/oci-test.json[3]build
=== RUN   TestPurlSpecFixtures/oci-test.json[4]parse
=== RUN   TestPurlSpecFixtures/oci-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/oci-test.json[6]build
=== RUN   TestPurlSpecFixtures/oci-test.json[7]parse
=== RUN   TestPurlSpecFixtures/oci-test.json[8]roundtrip
=== RUN   TestPurlSpecFixtures/oci-test.json[9]build
=== RUN   TestPurlSpecFixtures/oci-test.json[10]parse
=== RUN   TestPurlSpecFixtures/oci-test.json[11]roundtrip
=== RUN   TestPurlSpecFixtures/oci-test.json[12]build
=== RUN   TestPurlSpecFixtures/pub-test.json[1]parse
=== RUN   TestPurlSpecFixtures/pub-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/pub-test.json[3]build
=== RUN   TestPurlSpecFixtures/pub-test.json[4]parse
=== RUN   TestPurlSpecFixtures/pub-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/pub-test.json[6]build
=== RUN   TestPurlSpecFixtures/pypi-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/pypi-test.json[2]parse
=== RUN   TestPurlSpecFixtures/pypi-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/pypi-test.json[4]build
=== RUN   TestPurlSpecFixtures/pypi-test.json[5]parse
=== RUN   TestPurlSpecFixtures/pypi-test.json[6]roundtrip
=== RUN   TestPurlSpecFixtures/pypi-test.json[7]build
=== RUN   TestPurlSpecFixtures/pypi-test.json[8]parse
=== RUN   TestPurlSpecFixtures/pypi-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/pypi-test.json[10]build
=== RUN   TestPurlSpecFixtures/pypi-test.json[11]parse
=== RUN   TestPurlSpecFixtures/pypi-test.json[12]roundtrip
=== RUN   TestPurlSpecFixtures/pypi-test.json[13]build
=== RUN   TestPurlSpecFixtures/pypi-test.json[14]parse
=== RUN   TestPurlSpecFixtures/pypi-test.json[15]roundtrip
=== RUN   TestPurlSpecFixtures/pypi-test.json[16]build
=== RUN   TestPurlSpecFixtures/qpkg-test.json[1]parse
=== RUN   TestPurlSpecFixtures/qpkg-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/qpkg-test.json[3]build
=== RUN   TestPurlSpecFixtures/qpkg-test.json[4]parse
=== RUN   TestPurlSpecFixtures/qpkg-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/qpkg-test.json[6]build
=== RUN   TestPurlSpecFixtures/rpm-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/rpm-test.json[2]parse
=== RUN   TestPurlSpecFixtures/rpm-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/rpm-test.json[4]build
=== RUN   TestPurlSpecFixtures/rpm-test.json[5]parse
=== RUN   TestPurlSpecFixtures/rpm-test.json[6]roundtrip
=== RUN   TestPurlSpecFixtures/rpm-test.json[7]build
=== RUN   TestPurlSpecFixtures/rpm-test.json[8]parse
=== RUN   TestPurlSpecFixtures/rpm-test.json[9]roundtrip
=== RUN   TestPurlSpecFixtures/rpm-test.json[10]build
=== RUN   TestPurlSpecFixtures/swid-test.json[1]parse
=== RUN   TestPurlSpecFixtures/swid-test.json[2]roundtrip
=== RUN   TestPurlSpecFixtures/swid-test.json[3]build
=== RUN   TestPurlSpecFixtures/swid-test.json[4]parse
=== RUN   TestPurlSpecFixtures/swid-test.json[5]roundtrip
=== RUN   TestPurlSpecFixtures/swid-test.json[6]build
=== RUN   TestPurlSpecFixtures/swid-test.json[7]parse
=== RUN   TestPurlSpecFixtures/swid-test.json[8]roundtrip
=== RUN   TestPurlSpecFixtures/swid-test.json[9]build
=== RUN   TestPurlSpecFixtures/swift-test.json[1]roundtrip
=== RUN   TestPurlSpecFixtures/swift-test.json[2]parse
=== RUN   TestPurlSpecFixtures/swift-test.json[3]roundtrip
=== RUN   TestPurlSpecFixtures/swift-test.json[4]build
=== RUN   TestPurlSpecFixtures/swift-test.json[5]parse
=== RUN   TestPurlSpecFixtures/swift-test.json[6]parse
=== RUN   TestPurlSpecFixtures/swift-test.json[7]build
=== RUN   TestPurlSpecFixtures/swift-test.json[8]parse
=== RUN   TestPurlSpecFixtures/swift-test.json[9]parse
=== RUN   TestPurlSpecFixtures/swift-test.json[10]build
=== RUN   TestPurlSpecFixtures/swift-test.json[11]parse
=== RUN   TestPurlSpecFixtures/swift-test.json[12]parse
=== RUN   TestPurlSpecFixtures/swift-test.json[13]build
=== RUN   TestPurlSpecFixtures/swift-test.json[14]parse
=== RUN   TestPurlSpecFixtures/swift-test.json[15]roundtrip
=== RUN   TestPurlSpecFixtures/swift-test.json[16]build
=== RUN   TestPurlSpecFixtures/swift-test.json[17]parse
=== RUN   TestPurlSpecFixtures/swift-test.json[18]roundtrip
=== RUN   TestPurlSpecFixtures/swift-test.json[19]build
--- PASS: TestPurlSpecFixtures (0.03s)
    --- PASS: TestPurlSpecFixtures/alpm-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/alpm-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/alpm-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/alpm-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/alpm-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/alpm-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/alpm-test.json[7]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/alpm-test.json[8]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/alpm-test.json[9]build (0.00s)
    --- PASS: TestPurlSpecFixtures/apk-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/apk-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/apk-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/apk-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/apk-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/apk-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[4]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[7]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[8]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[9]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[10]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[11]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[12]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[13]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[14]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[15]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[16]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[17]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[18]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[19]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[20]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bazel-test.json[21]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bitbucket-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bitbucket-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bitbucket-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bitbucket-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bitbucket-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bitbucket-test.json[6]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bitbucket-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[7]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[8]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[9]build (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[10]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[11]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/bitnami-test.json[12]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cargo-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cargo-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cargo-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cargo-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cargo-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cargo-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cargo-test.json[7]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cargo-test.json[8]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cargo-test.json[9]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[7]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[8]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[9]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[10]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[11]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cocoapods-test.json[12]build (0.00s)
    --- PASS: TestPurlSpecFixtures/composer-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/composer-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/composer-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/composer-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/composer-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/composer-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/composer-test.json[7]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/composer-test.json[8]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/composer-test.json[9]build (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[6]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[7]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[8]build (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[9]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[10]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[11]build (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[12]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[13]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[14]build (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[15]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[16]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/conan-test.json[17]build (0.00s)
    --- PASS: TestPurlSpecFixtures/conda-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/conda-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/conda-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/conda-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/conda-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/conda-test.json[6]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/conda-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[5]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[6]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[7]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[8]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[10]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[11]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[12]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[13]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[14]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[15]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[16]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[17]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[18]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cpan-test.json[19]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[6]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[8]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[10]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[11]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[12]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[13]build (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[14]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[15]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/cran-test.json[16]build (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[6]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[8]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[10]build (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[11]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[12]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[13]build (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[14]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[15]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[16]build (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[17]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[18]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/deb-test.json[19]build (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[6]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[8]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[10]build (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[11]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[12]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/docker-test.json[13]build (0.00s)
    --- PASS: TestPurlSpecFixtures/gem-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/gem-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/gem-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/gem-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/gem-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/gem-test.json[6]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/gem-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/gem-test.json[8]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/gem-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/gem-test.json[10]build (0.00s)
    --- PASS: TestPurlSpecFixtures/generic-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/generic-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/generic-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/generic-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/generic-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/generic-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/generic-test.json[7]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/generic-test.json[8]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/generic-test.json[9]build (0.00s)
    --- PASS: TestPurlSpecFixtures/github-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/github-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/github-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/github-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/github-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/github-test.json[6]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/github-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/github-test.json[8]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/github-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/github-test.json[10]build (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[6]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[7]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[8]build (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[9]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[10]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[11]build (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[12]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[13]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[14]build (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[15]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[16]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/golang-test.json[17]build (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[6]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[8]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[10]build (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[11]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[12]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[13]build (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[14]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[15]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/hackage-test.json[16]build (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[7]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[8]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[9]build (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[10]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[11]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/hex-test.json[12]build (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[6]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[7]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[8]build (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[10]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[11]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[12]build (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[13]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[14]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[15]build (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[16]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[17]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/huggingface-test.json[18]build (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[3]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[5]build (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[7]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[8]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[9]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[10]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[11]build (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[12]build (0.00s)
    --- PASS: TestPurlSpecFixtures/julia-test.json[13]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/luarocks-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/luarocks-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/luarocks-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/luarocks-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/luarocks-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/luarocks-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/luarocks-test.json[7]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/luarocks-test.json[8]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/luarocks-test.json[9]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[6]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[7]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[8]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[10]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[11]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[12]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[13]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[14]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[15]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[16]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[17]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[18]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[19]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[20]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[21]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[22]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[23]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[24]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[25]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[26]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[27]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[28]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[29]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[30]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[31]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[32]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[33]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[34]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[35]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[36]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[37]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[38]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[39]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[40]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[41]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[42]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[43]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[44]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[45]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[46]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[47]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[48]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[49]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[50]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[51]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[52]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[53]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[54]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[55]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[56]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[57]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[58]build (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[59]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[60]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/maven-test.json[61]build (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[6]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[7]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[8]build (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[10]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[11]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[12]build (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[13]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[14]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[15]build (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[16]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[17]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/mlflow-test.json[18]build (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[6]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[8]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[10]build (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[11]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[12]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[13]build (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[14]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[15]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[16]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/npm-test.json[17]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/nuget-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/nuget-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/nuget-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/nuget-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/nuget-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/nuget-test.json[6]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/nuget-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[7]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[8]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[9]build (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[10]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[11]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/oci-test.json[12]build (0.00s)
    --- PASS: TestPurlSpecFixtures/pub-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/pub-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/pub-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/pub-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/pub-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/pub-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[6]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[8]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[10]build (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[11]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[12]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[13]build (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[14]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[15]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/pypi-test.json[16]build (0.00s)
    --- PASS: TestPurlSpecFixtures/qpkg-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/qpkg-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/qpkg-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/qpkg-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/qpkg-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/qpkg-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/rpm-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/rpm-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/rpm-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/rpm-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/rpm-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/rpm-test.json[6]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/rpm-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/rpm-test.json[8]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/rpm-test.json[9]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/rpm-test.json[10]build (0.00s)
    --- PASS: TestPurlSpecFixtures/swid-test.json[1]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swid-test.json[2]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/swid-test.json[3]build (0.00s)
    --- PASS: TestPurlSpecFixtures/swid-test.json[4]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swid-test.json[5]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/swid-test.json[6]build (0.00s)
    --- PASS: TestPurlSpecFixtures/swid-test.json[7]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swid-test.json[8]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/swid-test.json[9]build (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[1]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[2]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[3]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[4]build (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[5]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[6]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[7]build (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[8]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[9]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[10]build (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[11]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[12]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[13]build (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[14]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[15]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[16]build (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[17]parse (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[18]roundtrip (0.00s)
    --- PASS: TestPurlSpecFixtures/swift-test.json[19]build (0.00s)
=== RUN   TestQualifiersMapConversion
--- PASS: TestQualifiersMapConversion (0.00s)
=== RUN   TestNameEscaping
=== RUN   TestNameEscaping/abc
=== RUN   TestNameEscaping/ab/c
--- PASS: TestNameEscaping (0.00s)
    --- PASS: TestNameEscaping/abc (0.00s)
    --- PASS: TestNameEscaping/ab/c (0.00s)
=== RUN   TestQualifierMissingEqual
--- PASS: TestQualifierMissingEqual (0.00s)
=== RUN   TestNormalize
=== RUN   TestNormalize/type_is_case_insensitive
=== RUN   TestNormalize/type_is_manditory
=== RUN   TestNormalize/leading_and_traling_/_on_namespace_are_trimmed
=== RUN   TestNormalize/qualifiers_with_empty_values_are_removed
=== RUN   TestNormalize/qualifiers_are_sorted_by_key
=== RUN   TestNormalize/duplicate_keys_are_invalid
=== RUN   TestNormalize/keys_are_made_lower_case
=== RUN   TestNormalize/name_is_required
=== RUN   TestNormalize/leading_and_traling_/_on_subpath_are_trimmed
=== RUN   TestNormalize/'.'_is_an_invalid_subpath_segment
=== RUN   TestNormalize/'..'_is_an_invalid_subpath_segment
=== RUN   TestNormalize/'./'_is_a_valid_subpath_prefix
=== RUN   TestNormalize/'../'_is_a_valid_subpath_prefix
=== RUN   TestNormalize/known_type_namespace_adjustments
=== RUN   TestNormalize/known_type_name_adjustments
=== RUN   TestNormalize/known_type_version_adjustments
--- PASS: TestNormalize (0.00s)
    --- PASS: TestNormalize/type_is_case_insensitive (0.00s)
    --- PASS: TestNormalize/type_is_manditory (0.00s)
    --- PASS: TestNormalize/leading_and_traling_/_on_namespace_are_trimmed (0.00s)
    --- PASS: TestNormalize/qualifiers_with_empty_values_are_removed (0.00s)
    --- PASS: TestNormalize/qualifiers_are_sorted_by_key (0.00s)
    --- PASS: TestNormalize/duplicate_keys_are_invalid (0.00s)
    --- PASS: TestNormalize/keys_are_made_lower_case (0.00s)
    --- PASS: TestNormalize/name_is_required (0.00s)
    --- PASS: TestNormalize/leading_and_traling_/_on_subpath_are_trimmed (0.00s)
    --- PASS: TestNormalize/'.'_is_an_invalid_subpath_segment (0.00s)
    --- PASS: TestNormalize/'..'_is_an_invalid_subpath_segment (0.00s)
    --- PASS: TestNormalize/'./'_is_a_valid_subpath_prefix (0.00s)
    --- PASS: TestNormalize/'../'_is_a_valid_subpath_prefix (0.00s)
    --- PASS: TestNormalize/known_type_namespace_adjustments (0.00s)
    --- PASS: TestNormalize/known_type_name_adjustments (0.00s)
    --- PASS: TestNormalize/known_type_version_adjustments (0.00s)
=== RUN   FuzzFromString
=== RUN   FuzzFromString/771e938e4458e983a736261a702e27c7a414fd660a15b63034f290b146d2f217
0=== RUN   FuzzFromString/d0a861fe9b7c443af2b649e08753442111b630dd29fcd570543db3f9351158aa
?A--- PASS: FuzzFromString (0.00s)
    --- PASS: FuzzFromString/771e938e4458e983a736261a702e27c7a414fd660a15b63034f290b146d2f217 (0.00s)
    --- PASS: FuzzFromString/d0a861fe9b7c443af2b649e08753442111b630dd29fcd570543db3f9351158aa (0.00s)
PASS
coverage: 90.1% of statements
ok  	github.com/package-url/packageurl-go	(cached)	coverage: 90.1% of statements
	github.com/package-url/packageurl-go/examples/roundtrip		coverage: 0.0% of statements

@petergardfjall
Copy link
Collaborator Author

I think this can be merged now. It includes #80.

@shibumi
Copy link
Collaborator

shibumi commented Dec 3, 2025

Unit tests are failing. Can you take a look?

@petergardfjall
Copy link
Collaborator Author

petergardfjall commented Dec 3, 2025

Unit tests are failing. Can you take a look?

Yes, I tried to explain that in #83 (comment) but maybe it went unnoticed in the wall of text. 😅

There are still a dozen failing tests which are due to bad testcases upstream in the purl-spec. PRs are opened to fix (mostly remove) those:

Until that happens these tests will keep failing.

@shibumi
Copy link
Collaborator

shibumi commented Dec 3, 2025

I approved all purl-spec PRs, but I am sadly not a purl-spec maintainer. This means, you will have to reach out to @pombredanne or someone else

@petergardfjall
Copy link
Collaborator Author

petergardfjall commented Dec 4, 2025

@pombredanne
Copy link
Member

I approved all purl-spec PRs, but I am sadly not a purl-spec maintainer. This means, you will have to reach out to @pombredanne or someone else

Let me review and merge these ASAP!

but I am sadly not a purl-spec maintainer

@shibumi you have been a long time contributor.... would you want to join as a spec helper too?

@shibumi
Copy link
Collaborator

shibumi commented Dec 6, 2025

@shibumi you have been a long time contributor.... would you want to join as a spec helper too?

Depends how time consuming it is :) Would be an honor.

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.

4 participants