diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..805885b --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +.PHONY: harvest + +harvest: + go run ./tools/harvest $(HARVEST_ARGS) diff --git a/composer_pub.go b/composer_pub.go index b2e3486..08ff3b4 100644 --- a/composer_pub.go +++ b/composer_pub.go @@ -12,7 +12,7 @@ var ( composerNumericBranchRegex = regexp.MustCompile(`(?i)^v?\d+(?:\.\d+)*\.x-dev$`) composerOrRegex = regexp.MustCompile(`\s*\|\|?\s*`) composerStabilityFlagRegex = regexp.MustCompile(`(?i)^(.*?)@(dev|alpha|beta|rc|stable)$`) - composerVersionRegex = regexp.MustCompile(`(?i)^v?([0-9]+(?:\.[0-9]+){0,3})(?:[-._]?([a-z]+)(?:[.-]?([0-9]+))?)?(?:\+[^\s]+)?$`) + composerVersionRegex = regexp.MustCompile(`(?i)^v?([0-9]+(?:\.[0-9]+){0,3})(?:[-._]?([a-z]+)(?:[.-]?([0-9]+(?:[.-][0-9]+)*))?)?(?:\+[^\s]+)?$`) pubVersionPrefixRegex = regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?`) ) @@ -412,6 +412,14 @@ func parseComposerVersion(version string) (composerVersion, bool) { func compareComposer(a, b string) int { left, leftOK := parseComposerVersion(a) right, rightOK := parseComposerVersion(b) + leftBranch := strings.HasPrefix(strings.ToLower(a), "dev-") + rightBranch := strings.HasPrefix(strings.ToLower(b), "dev-") + if leftBranch != rightBranch { + if leftBranch { + return -1 + } + return 1 + } if !leftOK || !rightOK { return cmpString(strings.ToLower(a), strings.ToLower(b)) } @@ -423,7 +431,25 @@ func compareComposer(a, b string) int { if left.stability != right.stability { return cmpInt(left.stability, right.stability) } - return cmpNumStr(left.number, right.number) + return compareComposerNumbers(left.number, right.number) +} + +func compareComposerNumbers(a, b string) int { + left := strings.FieldsFunc(a, func(character rune) bool { return character == '.' || character == '-' }) + right := strings.FieldsFunc(b, func(character rune) bool { return character == '.' || character == '-' }) + for index := 0; index < len(left) || index < len(right); index++ { + var leftPart, rightPart string + if index < len(left) { + leftPart = left[index] + } + if index < len(right) { + rightPart = right[index] + } + if comparison := cmpNumStr(leftPart, rightPart); comparison != 0 { + return comparison + } + } + return 0 } // validComposerVersion reports whether a version is a numeric Composer version diff --git a/composer_pub_test.go b/composer_pub_test.go index 3db9f0a..5329792 100644 --- a/composer_pub_test.go +++ b/composer_pub_test.go @@ -68,6 +68,23 @@ func TestNormalizeComposerAndPubVersions(t *testing.T) { } } +func TestComposerComparisonNormalizesStabilityNumbers(t *testing.T) { + tests := []struct { + left, right string + want int + }{ + {left: "1.25.0-beta2.1", right: "1.25.0-b.3", want: -1}, + {left: "1.25.0-beta2.1", right: "1.25.0-b.2.1", want: 0}, + {left: "1.25.0beta2.1", right: "1.25.0-b2.1", want: 0}, + {left: "dev-main", right: "1.0.0", want: -1}, + } + for _, test := range tests { + if got := CompareWithScheme(test.left, test.right, schemeComposer); got != test.want { + t.Errorf("CompareWithScheme(%q, %q, composer) = %d, want %d", test.left, test.right, got, test.want) + } + } +} + func TestComposerAndPubVersRoundTrip(t *testing.T) { tests := []struct { constraint string diff --git a/schemes.go b/schemes.go index ab9f5c3..a7960ba 100644 --- a/schemes.go +++ b/schemes.go @@ -23,6 +23,171 @@ func compareSemver(a, b string) int { return compareSemverPrereleaseStrings(va.pre, vb.pre) } +func compareNPM(a, b string) int { + return compareSemver(strings.TrimSpace(a), strings.TrimSpace(b)) +} + +func compareCargo(a, b string) int { + comparison := compareSemver(a, b) + if comparison != 0 { + return comparison + } + return compareCargoBuild(semverBuild(a), semverBuild(b)) +} + +func semverBuild(version string) string { + if index := strings.IndexByte(version, '+'); index >= 0 { + return version[index+1:] + } + return "" +} + +func compareCargoBuild(a, b string) int { + if a == b { + return 0 + } + if a == "" { + return -1 + } + if b == "" { + return 1 + } + + left := strings.Split(a, ".") + right := strings.Split(b, ".") + for index := 0; index < len(left) && index < len(right); index++ { + if comparison := compareCargoBuildIdentifier(left[index], right[index]); comparison != 0 { + return comparison + } + } + return cmpInt(len(left), len(right)) +} + +func compareCargoBuildIdentifier(a, b string) int { + aNumeric, bNumeric := isDigits(a), isDigits(b) + if aNumeric != bNumeric { + if aNumeric { + return -1 + } + return 1 + } + if !aNumeric { + return cmpString(a, b) + } + left, right := trimLeadingZeros(a), trimLeadingZeros(b) + if comparison := cmpInt(len(left), len(right)); comparison != 0 { + return comparison + } + if comparison := cmpString(left, right); comparison != 0 { + return comparison + } + return cmpInt(len(a), len(b)) +} + +func compareGo(a, b string) int { + if !strings.HasPrefix(a, "v") && !strings.HasPrefix(b, "v") { + return compareSemver(a, b) + } + left, leftOK := parseGoVersion(a) + right, rightOK := parseGoVersion(b) + if !leftOK || !rightOK { + switch { + case leftOK: + return 1 + case rightOK: + return -1 + default: + return 0 + } + } + for index := range left.core { + if comparison := cmpNumStr(left.core[index], right.core[index]); comparison != 0 { + return comparison + } + } + return compareSemverPrereleaseStrings(left.pre, right.pre) +} + +func parseGoVersion(version string) (semverValue, bool) { + if len(version) < 2 || version[0] != 'v' { + return semverValue{}, false + } + version = version[1:] + coreEnd := strings.IndexAny(version, "-+") + if coreEnd < 0 { + coreEnd = len(version) + } + core := strings.Split(version[:coreEnd], ".") + if len(core) > 3 || !validGoCore(core) { + return semverValue{}, false + } + if len(core) < 3 && coreEnd != len(version) { + return semverValue{}, false + } + for len(core) < 3 { + core = append(core, "0") + } + + parsed := semverValue{core: [3]string{core[0], core[1], core[2]}} + remainder := version[coreEnd:] + if strings.HasPrefix(remainder, "-") { + remainder = remainder[1:] + preEnd := strings.IndexByte(remainder, '+') + if preEnd < 0 { + preEnd = len(remainder) + } + parsed.pre = remainder[:preEnd] + if !validGoIdentifiers(parsed.pre, false) { + return semverValue{}, false + } + remainder = remainder[preEnd:] + } + if strings.HasPrefix(remainder, "+") { + if !validGoIdentifiers(remainder[1:], true) { + return semverValue{}, false + } + remainder = "" + } + return parsed, remainder == "" +} + +func validGoCore(parts []string) bool { + if len(parts) == 0 { + return false + } + for _, part := range parts { + if !isDigits(part) || len(part) > 1 && part[0] == '0' { + return false + } + } + return true +} + +func validGoIdentifiers(value string, build bool) bool { + if value == "" { + return false + } + for _, identifier := range strings.Split(value, ".") { + if identifier == "" || !validGoIdentifier(identifier) { + return false + } + if !build && len(identifier) > 1 && identifier[0] == '0' && isDigits(identifier) { + return false + } + } + return true +} + +func validGoIdentifier(identifier string) bool { + for index := range len(identifier) { + character := identifier[index] + if !isASCIIAlnum(character) && character != '-' { + return false + } + } + return true +} + func parseSemverValue(s string) (semverValue, bool) { var v semverValue i := 0 diff --git a/schemes_test.go b/schemes_test.go index f613806..a9f9268 100644 --- a/schemes_test.go +++ b/schemes_test.go @@ -90,7 +90,7 @@ func TestSemverSchemeComparison(t *testing.T) { {"999999999999999999999999.0.0", "888888888888888888888888.0.0", 1}, {"1.0.0+one", "1.0.0+two", 0}, } - for _, scheme := range []string{"semver", "npm", "cargo", "go", "golang", "hex", "elixir"} { + for _, scheme := range []string{"semver", "npm", "hex", "elixir"} { for _, tt := range tests { if got := CompareWithScheme(tt.a, tt.b, scheme); got != tt.want { t.Errorf("CompareWithScheme(%q, %q, %q) = %d, want %d", tt.a, tt.b, scheme, got, tt.want) @@ -102,6 +102,28 @@ func TestSemverSchemeComparison(t *testing.T) { } } +func TestEcosystemSemverDifferences(t *testing.T) { + tests := []struct { + scheme, a, b string + want int + }{ + {scheme: schemeNPM, a: " v1.2.3+one", b: "1.2.3+two", want: 0}, + {scheme: schemeCargo, a: "1.2.3+23", b: "1.2.3+42", want: -1}, + {scheme: schemeCargo, a: "1.2.3", b: "1.2.3+0", want: -1}, + {scheme: schemeCargo, a: "1.2.3+0", b: "1.2.3+00", want: -1}, + {scheme: schemeGo, a: "bad", b: "v1-pre", want: 0}, + {scheme: schemeGo, a: "bad", b: "v1.0.0-alpha", want: -1}, + {scheme: schemeGo, a: "v1", b: "v1.0.0", want: 0}, + {scheme: schemeGo, a: "1.9.9", b: "2.0.0", want: -1}, + {scheme: schemeGolang, a: "v1.2.3+one", b: "v1.2.3+two", want: 0}, + } + for _, test := range tests { + if got := CompareWithScheme(test.a, test.b, test.scheme); got != test.want { + t.Errorf("CompareWithScheme(%q, %q, %q) = %d, want %d", test.a, test.b, test.scheme, got, test.want) + } + } +} + func TestDatetimeSchemeComparison(t *testing.T) { tests := []struct { a, b string @@ -128,6 +150,7 @@ func TestGemSchemeComparison(t *testing.T) { {"1.0.a10", "1.0.a2", 1}, {"1.0-1", "1.0.pre.1", 0}, {"1.0", "1.0.0", 0}, + {"", "0", 0}, } for _, scheme := range []string{"gem", "rubygems"} { for _, tt := range tests { diff --git a/testdata/local/provenance.json b/testdata/local/provenance.json index efd5f3b..a9dbdd9 100644 --- a/testdata/local/provenance.json +++ b/testdata/local/provenance.json @@ -4,15 +4,115 @@ "repository": "https://github.com/git-pkgs/vers", "commit": "aca1342a0af1b6308ced629af1913ab42a66dbb5", "license": "MIT", - "source_file": "composer_pub_test.go", + "source_files": [ + "composer_pub_test.go" + ], "generated_files": [ "tests/composer_range_containment_test.json", "tests/composer_range_from_native_test.json", - "tests/composer_version_cmp_test.json", "tests/pub_range_containment_test.json", - "tests/pub_range_from_native_test.json", + "tests/pub_range_from_native_test.json" + ] + }, + { + "repository": "https://github.com/npm/node-semver.git", + "commit": "6e05b7637396ac66522cff8731f07cfe0ef49a29", + "license": "ISC", + "source_files": [ + "test/fixtures/comparisons.js", + "test/fixtures/equality.js" + ], + "generated_files": [ + "tests/npm_version_cmp_test.json" + ] + }, + { + "repository": "https://github.com/pypa/packaging.git", + "commit": "55cbf1b9426f44455fa1a9e0836f1fc082cc8452", + "license": "Apache-2.0 OR BSD-2-Clause", + "source_files": [ + "tests/test_version.py" + ], + "generated_files": [ + "tests/pypi_version_cmp_test.json" + ] + }, + { + "repository": "https://github.com/rubygems/rubygems.git", + "commit": "370fe6876eec1714cd0f8824c3f19f4d368dfe7c", + "license": "MIT", + "source_files": [ + "test/rubygems/test_gem_version.rb" + ], + "generated_files": [ + "tests/gem_version_cmp_test.json" + ] + }, + { + "repository": "https://github.com/composer/semver.git", + "commit": "1cbc9b575a27458074d21a3bab95b847c8de387c", + "license": "MIT", + "source_files": [ + "tests/ComparatorTest.php" + ], + "generated_files": [ + "tests/composer_version_cmp_test.json" + ] + }, + { + "repository": "https://github.com/dart-lang/tools.git", + "commit": "a22c3a687dc1b35630fb34c296157d66565429cd", + "license": "BSD-3-Clause", + "source_files": [ + "pkgs/pub_semver/test/version_test.dart" + ], + "generated_files": [ "tests/pub_version_cmp_test.json" ] + }, + { + "repository": "https://github.com/dtolnay/semver.git", + "commit": "280ebcb6edac3aa4cdc545dbff8a26c5ac4861fe", + "license": "MIT OR Apache-2.0", + "source_files": [ + "tests/test_version.rs" + ], + "generated_files": [ + "tests/cargo_version_cmp_test.json" + ] + }, + { + "repository": "https://salsa.debian.org/dpkg-team/dpkg.git", + "commit": "c5efef926d16a72fd9270c8efceeba8872419292", + "license": "GPL-2.0-or-later", + "source_files": [ + "lib/dpkg/t/t-version.c" + ], + "generated_files": [ + "tests/deb_version_cmp_test.json" + ] + }, + { + "repository": "https://github.com/rpm-software-management/rpm.git", + "commit": "ac5062c43e2337fb43a9179f02c0cc5d7d069802", + "license": "GPL-2.0-or-later", + "source_files": [ + "tests/rpmvercmp.at" + ], + "generated_files": [ + "tests/rpm_version_cmp_test.json" + ] + }, + { + "repository": "https://github.com/golang/mod.git", + "commit": "d3398d06de5fa5c71083d3d1c26f2cda73508e0f", + "license": "BSD-3-Clause", + "source_files": [ + "semver/semver_test.go" + ], + "generated_files": [ + "tests/go_version_cmp_test.json" + ] } ] } diff --git a/testdata/local/tests/cargo_version_cmp_test.json b/testdata/local/tests/cargo_version_cmp_test.json new file mode 100644 index 0000000..75c6e09 --- /dev/null +++ b/testdata/local/tests/cargo_version_cmp_test.json @@ -0,0 +1,434 @@ +{ + "$schema": "https://packageurl.org/schemas/vers-test.schema-0.2.json", + "tests": [ + { + "description": "semver orders \"1.0.0-alpha\" before \"1.0.0-alpha.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-alpha.1", + "1.0.0-alpha" + ] + }, + "expected_output": [ + "1.0.0-alpha", + "1.0.0-alpha.1" + ] + }, + { + "description": "semver treats \"1.0.0-alpha\" and \"1.0.0-alpha.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-alpha", + "1.0.0-alpha.1" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"1.0.0-alpha.1\" before \"1.0.0-alpha.beta\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-alpha.beta", + "1.0.0-alpha.1" + ] + }, + "expected_output": [ + "1.0.0-alpha.1", + "1.0.0-alpha.beta" + ] + }, + { + "description": "semver treats \"1.0.0-alpha.1\" and \"1.0.0-alpha.beta\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-alpha.1", + "1.0.0-alpha.beta" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"1.0.0-alpha.beta\" before \"1.0.0-beta\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-beta", + "1.0.0-alpha.beta" + ] + }, + "expected_output": [ + "1.0.0-alpha.beta", + "1.0.0-beta" + ] + }, + { + "description": "semver treats \"1.0.0-alpha.beta\" and \"1.0.0-beta\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-alpha.beta", + "1.0.0-beta" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"1.0.0-beta\" before \"1.0.0-beta.2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-beta.2", + "1.0.0-beta" + ] + }, + "expected_output": [ + "1.0.0-beta", + "1.0.0-beta.2" + ] + }, + { + "description": "semver treats \"1.0.0-beta\" and \"1.0.0-beta.2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-beta", + "1.0.0-beta.2" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"1.0.0-beta.2\" before \"1.0.0-beta.11\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-beta.11", + "1.0.0-beta.2" + ] + }, + "expected_output": [ + "1.0.0-beta.2", + "1.0.0-beta.11" + ] + }, + { + "description": "semver treats \"1.0.0-beta.2\" and \"1.0.0-beta.11\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-beta.2", + "1.0.0-beta.11" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"1.0.0-beta.11\" before \"1.0.0-rc.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-rc.1", + "1.0.0-beta.11" + ] + }, + "expected_output": [ + "1.0.0-beta.11", + "1.0.0-rc.1" + ] + }, + { + "description": "semver treats \"1.0.0-beta.11\" and \"1.0.0-rc.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-beta.11", + "1.0.0-rc.1" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"1.0.0-rc.1\" before \"1.0.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0", + "1.0.0-rc.1" + ] + }, + "expected_output": [ + "1.0.0-rc.1", + "1.0.0" + ] + }, + { + "description": "semver treats \"1.0.0-rc.1\" and \"1.0.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0-rc.1", + "1.0.0" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"0.0.0\" before \"1.2.3-alpha2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.2.3-alpha2", + "0.0.0" + ] + }, + "expected_output": [ + "0.0.0", + "1.2.3-alpha2" + ] + }, + { + "description": "semver treats \"0.0.0\" and \"1.2.3-alpha2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "0.0.0", + "1.2.3-alpha2" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"1.0.0\" before \"1.2.3-alpha2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.2.3-alpha2", + "1.0.0" + ] + }, + "expected_output": [ + "1.0.0", + "1.2.3-alpha2" + ] + }, + { + "description": "semver treats \"1.0.0\" and \"1.2.3-alpha2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.0.0", + "1.2.3-alpha2" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"1.2.0\" before \"1.2.3-alpha2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.2.3-alpha2", + "1.2.0" + ] + }, + "expected_output": [ + "1.2.0", + "1.2.3-alpha2" + ] + }, + { + "description": "semver treats \"1.2.0\" and \"1.2.3-alpha2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.2.0", + "1.2.3-alpha2" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"1.2.3-alpha1\" before \"1.2.3\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.2.3", + "1.2.3-alpha1" + ] + }, + "expected_output": [ + "1.2.3-alpha1", + "1.2.3" + ] + }, + { + "description": "semver treats \"1.2.3-alpha1\" and \"1.2.3\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.2.3-alpha1", + "1.2.3" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"1.2.3-alpha1\" before \"1.2.3-alpha2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.2.3-alpha2", + "1.2.3-alpha1" + ] + }, + "expected_output": [ + "1.2.3-alpha1", + "1.2.3-alpha2" + ] + }, + { + "description": "semver treats \"1.2.3-alpha1\" and \"1.2.3-alpha2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.2.3-alpha1", + "1.2.3-alpha2" + ] + }, + "expected_output": false + }, + { + "description": "semver orders \"1.2.3+23\" before \"1.2.3+42\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "cargo", + "versions": [ + "1.2.3+42", + "1.2.3+23" + ] + }, + "expected_output": [ + "1.2.3+23", + "1.2.3+42" + ] + }, + { + "description": "semver treats \"1.2.3+23\" and \"1.2.3+42\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.2.3+23", + "1.2.3+42" + ] + }, + "expected_output": false + }, + { + "description": "semver treats \"0.0.0\" and \"0.0.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "0.0.0", + "0.0.1" + ] + }, + "expected_output": false + }, + { + "description": "semver treats \"0.0.0\" and \"0.1.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "0.0.0", + "0.1.0" + ] + }, + "expected_output": false + }, + { + "description": "semver treats \"0.0.0\" and \"1.0.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "0.0.0", + "1.0.0" + ] + }, + "expected_output": false + }, + { + "description": "semver treats \"1.2.3-alpha\" and \"1.2.3-beta\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "cargo", + "versions": [ + "1.2.3-alpha", + "1.2.3-beta" + ] + }, + "expected_output": false + } + ] +} diff --git a/testdata/local/tests/composer_range_from_native_test.json b/testdata/local/tests/composer_range_from_native_test.json index de63b63..8d62413 100644 --- a/testdata/local/tests/composer_range_from_native_test.json +++ b/testdata/local/tests/composer_range_from_native_test.json @@ -109,7 +109,7 @@ "type": "composer", "native_range": "dev-main as 2.x-dev || ^2.0" }, - "expected_output": "vers:composer/>=2.0.0-dev|<3.0.0-dev|dev-main" + "expected_output": "vers:composer/dev-main|>=2.0.0-dev|<3.0.0-dev" }, { "description": "Composer converts a single-pipe union.", diff --git a/testdata/local/tests/composer_version_cmp_test.json b/testdata/local/tests/composer_version_cmp_test.json index 4d93b8a..edc4910 100644 --- a/testdata/local/tests/composer_version_cmp_test.json +++ b/testdata/local/tests/composer_version_cmp_test.json @@ -2,42 +2,259 @@ "$schema": "https://packageurl.org/schemas/vers-test.schema-0.2.json", "tests": [ { - "description": "Composer orders stability qualifiers.", + "description": "composer/semver orders \"1.24.0\" before \"1.25.0\".", "test_group": "recommended", "test_type": "comparison", "input": { "input_type": "composer", "versions": [ - "1.0.0", - "1.0.0-beta1", - "1.0.0-dev", - "1.0.0-RC1", - "1.0.0-alpha2" + "1.25.0", + "1.24.0" ] }, "expected_output": [ - "1.0.0-dev", - "1.0.0-alpha2", - "1.0.0-beta1", - "1.0.0-RC1", - "1.0.0" + "1.24.0", + "1.25.0" ] }, { - "description": "Composer orders numeric stability suffixes numerically.", + "description": "composer/semver treats \"1.25.0\" and \"1.24.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "composer", + "versions": [ + "1.25.0", + "1.24.0" + ] + }, + "expected_output": false + }, + { + "description": "composer/semver orders \"1.25.0\" before \"1.26.0\".", "test_group": "recommended", "test_type": "comparison", "input": { "input_type": "composer", "versions": [ - "1.0.0-beta10", - "1.0.0-beta2" + "1.26.0", + "1.25.0" ] }, "expected_output": [ - "1.0.0-beta2", - "1.0.0-beta10" + "1.25.0", + "1.26.0" ] + }, + { + "description": "composer/semver treats \"1.25.0\" and \"1.26.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "composer", + "versions": [ + "1.25.0", + "1.26.0" + ] + }, + "expected_output": false + }, + { + "description": "composer/semver orders \"1.25.0-beta2.1\" before \"1.25.0-b.3\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "composer", + "versions": [ + "1.25.0-b.3", + "1.25.0-beta2.1" + ] + }, + "expected_output": [ + "1.25.0-beta2.1", + "1.25.0-b.3" + ] + }, + { + "description": "composer/semver treats \"1.25.0-beta2.1\" and \"1.25.0-b.3\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "composer", + "versions": [ + "1.25.0-beta2.1", + "1.25.0-b.3" + ] + }, + "expected_output": false + }, + { + "description": "composer/semver orders \"1.25.0-b2.1\" before \"1.25.0beta.3\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "composer", + "versions": [ + "1.25.0beta.3", + "1.25.0-b2.1" + ] + }, + "expected_output": [ + "1.25.0-b2.1", + "1.25.0beta.3" + ] + }, + { + "description": "composer/semver treats \"1.25.0-b2.1\" and \"1.25.0beta.3\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "composer", + "versions": [ + "1.25.0-b2.1", + "1.25.0beta.3" + ] + }, + "expected_output": false + }, + { + "description": "composer/semver orders \"1.25.0-b-2.1\" before \"1.25.0-rc\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "composer", + "versions": [ + "1.25.0-rc", + "1.25.0-b-2.1" + ] + }, + "expected_output": [ + "1.25.0-b-2.1", + "1.25.0-rc" + ] + }, + { + "description": "composer/semver treats \"1.25.0-b-2.1\" and \"1.25.0-rc\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "composer", + "versions": [ + "1.25.0-b-2.1", + "1.25.0-rc" + ] + }, + "expected_output": false + }, + { + "description": "composer/semver treats \"1.25.0-beta2.1\" and \"1.25.0-b.2.1\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "composer", + "versions": [ + "1.25.0-beta2.1", + "1.25.0-b.2.1" + ] + }, + "expected_output": true + }, + { + "description": "composer/semver treats \"1.25.0beta2.1\" and \"1.25.0-b2.1\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "composer", + "versions": [ + "1.25.0beta2.1", + "1.25.0-b2.1" + ] + }, + "expected_output": true + }, + { + "description": "composer/semver orders \"dev-foo\" before \"1.26.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "composer", + "versions": [ + "1.26.0", + "dev-foo" + ] + }, + "expected_output": [ + "dev-foo", + "1.26.0" + ] + }, + { + "description": "composer/semver treats \"1.26.0\" and \"dev-foo\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "composer", + "versions": [ + "1.26.0", + "dev-foo" + ] + }, + "expected_output": false + }, + { + "description": "composer/semver orders \"1.0.0\" before \"1.2-dev\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "composer", + "versions": [ + "1.2-dev", + "1.0.0" + ] + }, + "expected_output": [ + "1.0.0", + "1.2-dev" + ] + }, + { + "description": "composer/semver treats \"1.0.0\" and \"1.2-dev\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "composer", + "versions": [ + "1.0.0", + "1.2-dev" + ] + }, + "expected_output": false + }, + { + "description": "composer/semver treats \"dev-foo\" and \"dev-master\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "composer", + "versions": [ + "dev-foo", + "dev-master" + ] + }, + "expected_output": false + }, + { + "description": "composer/semver treats \"dev-foo\" and \"dev-bar\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "composer", + "versions": [ + "dev-foo", + "dev-bar" + ] + }, + "expected_output": false } ] } diff --git a/testdata/local/tests/deb_version_cmp_test.json b/testdata/local/tests/deb_version_cmp_test.json new file mode 100644 index 0000000..ef92bd8 --- /dev/null +++ b/testdata/local/tests/deb_version_cmp_test.json @@ -0,0 +1,105 @@ +{ + "$schema": "https://packageurl.org/schemas/vers-test.schema-0.2.json", + "tests": [ + { + "description": "dpkg treats \"0-00\" and \"00-0\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "deb", + "versions": [ + "0-00", + "00-0" + ] + }, + "expected_output": true + }, + { + "description": "dpkg orders \"0-0\" before \"1:0-0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "deb", + "versions": [ + "1:0-0", + "0-0" + ] + }, + "expected_output": [ + "0-0", + "1:0-0" + ] + }, + { + "description": "dpkg treats \"0-0\" and \"1:0-0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "deb", + "versions": [ + "0-0", + "1:0-0" + ] + }, + "expected_output": false + }, + { + "description": "dpkg orders \"a-0\" before \"b-0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "deb", + "versions": [ + "b-0", + "a-0" + ] + }, + "expected_output": [ + "a-0", + "b-0" + ] + }, + { + "description": "dpkg treats \"a-0\" and \"b-0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "deb", + "versions": [ + "a-0", + "b-0" + ] + }, + "expected_output": false + }, + { + "description": "dpkg orders \"0-a\" before \"0-b\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "deb", + "versions": [ + "0-b", + "0-a" + ] + }, + "expected_output": [ + "0-a", + "0-b" + ] + }, + { + "description": "dpkg treats \"0-a\" and \"0-b\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "deb", + "versions": [ + "0-a", + "0-b" + ] + }, + "expected_output": false + } + ] +} diff --git a/testdata/local/tests/gem_version_cmp_test.json b/testdata/local/tests/gem_version_cmp_test.json new file mode 100644 index 0000000..c552940 --- /dev/null +++ b/testdata/local/tests/gem_version_cmp_test.json @@ -0,0 +1,305 @@ +{ + "$schema": "https://packageurl.org/schemas/vers-test.schema-0.2.json", + "tests": [ + { + "description": "RubyGems treats \"1.0\" and \"1.0.0\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "1.0", + "1.0.0" + ] + }, + "expected_output": true + }, + { + "description": "RubyGems orders \"1.0.a\" before \"1.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "gem", + "versions": [ + "1.0", + "1.0.a" + ] + }, + "expected_output": [ + "1.0.a", + "1.0" + ] + }, + { + "description": "RubyGems treats \"1.0\" and \"1.0.a\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "1.0", + "1.0.a" + ] + }, + "expected_output": false + }, + { + "description": "RubyGems orders \"0.0.0\" before \"1.8.2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "gem", + "versions": [ + "1.8.2", + "0.0.0" + ] + }, + "expected_output": [ + "0.0.0", + "1.8.2" + ] + }, + { + "description": "RubyGems treats \"1.8.2\" and \"0.0.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "1.8.2", + "0.0.0" + ] + }, + "expected_output": false + }, + { + "description": "RubyGems orders \"1.8.2.a\" before \"1.8.2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "gem", + "versions": [ + "1.8.2", + "1.8.2.a" + ] + }, + "expected_output": [ + "1.8.2.a", + "1.8.2" + ] + }, + { + "description": "RubyGems treats \"1.8.2\" and \"1.8.2.a\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "1.8.2", + "1.8.2.a" + ] + }, + "expected_output": false + }, + { + "description": "RubyGems orders \"1.8.2.a\" before \"1.8.2.b\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "gem", + "versions": [ + "1.8.2.b", + "1.8.2.a" + ] + }, + "expected_output": [ + "1.8.2.a", + "1.8.2.b" + ] + }, + { + "description": "RubyGems treats \"1.8.2.b\" and \"1.8.2.a\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "1.8.2.b", + "1.8.2.a" + ] + }, + "expected_output": false + }, + { + "description": "RubyGems orders \"1.8.2.a9\" before \"1.8.2.a10\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "gem", + "versions": [ + "1.8.2.a10", + "1.8.2.a9" + ] + }, + "expected_output": [ + "1.8.2.a9", + "1.8.2.a10" + ] + }, + { + "description": "RubyGems treats \"1.8.2.a10\" and \"1.8.2.a9\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "1.8.2.a10", + "1.8.2.a9" + ] + }, + "expected_output": false + }, + { + "description": "RubyGems treats \"\" and \"0\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "", + "0" + ] + }, + "expected_output": true + }, + { + "description": "RubyGems treats \"0.beta.1\" and \"0.0.beta.1\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "0.beta.1", + "0.0.beta.1" + ] + }, + "expected_output": true + }, + { + "description": "RubyGems orders \"0.0.beta\" before \"0.0.beta.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "gem", + "versions": [ + "0.0.beta.1", + "0.0.beta" + ] + }, + "expected_output": [ + "0.0.beta", + "0.0.beta.1" + ] + }, + { + "description": "RubyGems treats \"0.0.beta\" and \"0.0.beta.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "0.0.beta", + "0.0.beta.1" + ] + }, + "expected_output": false + }, + { + "description": "RubyGems orders \"0.0.beta\" before \"0.beta.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "gem", + "versions": [ + "0.beta.1", + "0.0.beta" + ] + }, + "expected_output": [ + "0.0.beta", + "0.beta.1" + ] + }, + { + "description": "RubyGems treats \"0.0.beta\" and \"0.beta.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "0.0.beta", + "0.beta.1" + ] + }, + "expected_output": false + }, + { + "description": "RubyGems orders \"5.a\" before \"5.0.0.rc2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "gem", + "versions": [ + "5.0.0.rc2", + "5.a" + ] + }, + "expected_output": [ + "5.a", + "5.0.0.rc2" + ] + }, + { + "description": "RubyGems treats \"5.a\" and \"5.0.0.rc2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "5.a", + "5.0.0.rc2" + ] + }, + "expected_output": false + }, + { + "description": "RubyGems orders \"5.0.0.rc2\" before \"5.x\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "gem", + "versions": [ + "5.x", + "5.0.0.rc2" + ] + }, + "expected_output": [ + "5.0.0.rc2", + "5.x" + ] + }, + { + "description": "RubyGems treats \"5.x\" and \"5.0.0.rc2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "gem", + "versions": [ + "5.x", + "5.0.0.rc2" + ] + }, + "expected_output": false + } + ] +} diff --git a/testdata/local/tests/go_version_cmp_test.json b/testdata/local/tests/go_version_cmp_test.json new file mode 100644 index 0000000..bf252b9 --- /dev/null +++ b/testdata/local/tests/go_version_cmp_test.json @@ -0,0 +1,680 @@ +{ + "$schema": "https://packageurl.org/schemas/vers-test.schema-0.2.json", + "tests": [ + { + "description": "golang.org/x/mod/semver treats \"bad\" and \"v1-alpha.beta.gamma\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "bad", + "v1-alpha.beta.gamma" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver treats \"v1-alpha.beta.gamma\" and \"v1-pre\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1-alpha.beta.gamma", + "v1-pre" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver treats \"v1-pre\" and \"v1+meta\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1-pre", + "v1+meta" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver treats \"v1+meta\" and \"v1-pre+meta\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1+meta", + "v1-pre+meta" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver treats \"v1-pre+meta\" and \"v1.2-pre\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1-pre+meta", + "v1.2-pre" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2-pre\" and \"v1.2+meta\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2-pre", + "v1.2+meta" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2+meta\" and \"v1.2-pre+meta\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2+meta", + "v1.2-pre+meta" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver orders \"v1.2-pre+meta\" before \"v1.0.0-alpha\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-alpha", + "v1.2-pre+meta" + ] + }, + "expected_output": [ + "v1.2-pre+meta", + "v1.0.0-alpha" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2-pre+meta\" and \"v1.0.0-alpha\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2-pre+meta", + "v1.0.0-alpha" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.0.0-alpha\" before \"v1.0.0-alpha.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-alpha.1", + "v1.0.0-alpha" + ] + }, + "expected_output": [ + "v1.0.0-alpha", + "v1.0.0-alpha.1" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.0.0-alpha\" and \"v1.0.0-alpha.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-alpha", + "v1.0.0-alpha.1" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.0.0-alpha.1\" before \"v1.0.0-alpha.beta\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-alpha.beta", + "v1.0.0-alpha.1" + ] + }, + "expected_output": [ + "v1.0.0-alpha.1", + "v1.0.0-alpha.beta" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.0.0-alpha.1\" and \"v1.0.0-alpha.beta\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-alpha.1", + "v1.0.0-alpha.beta" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.0.0-alpha.beta\" before \"v1.0.0-beta\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-beta", + "v1.0.0-alpha.beta" + ] + }, + "expected_output": [ + "v1.0.0-alpha.beta", + "v1.0.0-beta" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.0.0-alpha.beta\" and \"v1.0.0-beta\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-alpha.beta", + "v1.0.0-beta" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.0.0-beta\" before \"v1.0.0-beta.2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-beta.2", + "v1.0.0-beta" + ] + }, + "expected_output": [ + "v1.0.0-beta", + "v1.0.0-beta.2" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.0.0-beta\" and \"v1.0.0-beta.2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-beta", + "v1.0.0-beta.2" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.0.0-beta.2\" before \"v1.0.0-beta.11\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-beta.11", + "v1.0.0-beta.2" + ] + }, + "expected_output": [ + "v1.0.0-beta.2", + "v1.0.0-beta.11" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.0.0-beta.2\" and \"v1.0.0-beta.11\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-beta.2", + "v1.0.0-beta.11" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.0.0-beta.11\" before \"v1.0.0-rc.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-rc.1", + "v1.0.0-beta.11" + ] + }, + "expected_output": [ + "v1.0.0-beta.11", + "v1.0.0-rc.1" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.0.0-beta.11\" and \"v1.0.0-rc.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-beta.11", + "v1.0.0-rc.1" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.0.0-rc.1\" before \"v1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1", + "v1.0.0-rc.1" + ] + }, + "expected_output": [ + "v1.0.0-rc.1", + "v1" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.0.0-rc.1\" and \"v1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0-rc.1", + "v1" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver treats \"v1\" and \"v1.0\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1", + "v1.0" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver treats \"v1.0\" and \"v1.0.0\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.0", + "v1.0.0" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver orders \"v1.0.0\" before \"v1.2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.2", + "v1.0.0" + ] + }, + "expected_output": [ + "v1.0.0", + "v1.2" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.0.0\" and \"v1.2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.0.0", + "v1.2" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2\" and \"v1.2.0\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2", + "v1.2.0" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver orders \"v1.2.0\" before \"v1.2.3-456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-456", + "v1.2.0" + ] + }, + "expected_output": [ + "v1.2.0", + "v1.2.3-456" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.0\" and \"v1.2.3-456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.0", + "v1.2.3-456" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.2.3-456\" before \"v1.2.3-456.789\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-456.789", + "v1.2.3-456" + ] + }, + "expected_output": [ + "v1.2.3-456", + "v1.2.3-456.789" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.3-456\" and \"v1.2.3-456.789\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-456", + "v1.2.3-456.789" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.2.3-456.789\" before \"v1.2.3-456-789\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-456-789", + "v1.2.3-456.789" + ] + }, + "expected_output": [ + "v1.2.3-456.789", + "v1.2.3-456-789" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.3-456.789\" and \"v1.2.3-456-789\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-456.789", + "v1.2.3-456-789" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.2.3-456-789\" before \"v1.2.3-456a\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-456a", + "v1.2.3-456-789" + ] + }, + "expected_output": [ + "v1.2.3-456-789", + "v1.2.3-456a" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.3-456-789\" and \"v1.2.3-456a\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-456-789", + "v1.2.3-456a" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.2.3-456a\" before \"v1.2.3-pre\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-pre", + "v1.2.3-456a" + ] + }, + "expected_output": [ + "v1.2.3-456a", + "v1.2.3-pre" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.3-456a\" and \"v1.2.3-pre\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-456a", + "v1.2.3-pre" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.3-pre\" and \"v1.2.3-pre+meta\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-pre", + "v1.2.3-pre+meta" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver orders \"v1.2.3-pre+meta\" before \"v1.2.3-pre.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-pre.1", + "v1.2.3-pre+meta" + ] + }, + "expected_output": [ + "v1.2.3-pre+meta", + "v1.2.3-pre.1" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.3-pre+meta\" and \"v1.2.3-pre.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-pre+meta", + "v1.2.3-pre.1" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.2.3-pre.1\" before \"v1.2.3-zzz\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-zzz", + "v1.2.3-pre.1" + ] + }, + "expected_output": [ + "v1.2.3-pre.1", + "v1.2.3-zzz" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.3-pre.1\" and \"v1.2.3-zzz\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-pre.1", + "v1.2.3-zzz" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver orders \"v1.2.3-zzz\" before \"v1.2.3\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3", + "v1.2.3-zzz" + ] + }, + "expected_output": [ + "v1.2.3-zzz", + "v1.2.3" + ] + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.3-zzz\" and \"v1.2.3\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3-zzz", + "v1.2.3" + ] + }, + "expected_output": false + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.3\" and \"v1.2.3+meta\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3", + "v1.2.3+meta" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.3+meta\" and \"v1.2.3+meta-pre\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3+meta", + "v1.2.3+meta-pre" + ] + }, + "expected_output": true + }, + { + "description": "golang.org/x/mod/semver treats \"v1.2.3+meta-pre\" and \"v1.2.3+meta-pre.sha.256a\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "go", + "versions": [ + "v1.2.3+meta-pre", + "v1.2.3+meta-pre.sha.256a" + ] + }, + "expected_output": true + } + ] +} diff --git a/testdata/local/tests/npm_version_cmp_test.json b/testdata/local/tests/npm_version_cmp_test.json new file mode 100644 index 0000000..870a5be --- /dev/null +++ b/testdata/local/tests/npm_version_cmp_test.json @@ -0,0 +1,595 @@ +{ + "$schema": "https://packageurl.org/schemas/vers-test.schema-0.2.json", + "tests": [ + { + "description": "node-semver orders \"0.0.0-foo\" before \"0.0.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "0.0.0", + "0.0.0-foo" + ] + }, + "expected_output": [ + "0.0.0-foo", + "0.0.0" + ] + }, + { + "description": "node-semver treats \"0.0.0\" and \"0.0.0-foo\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "0.0.0", + "0.0.0-foo" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"0.0.0\" before \"0.0.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "0.0.1", + "0.0.0" + ] + }, + "expected_output": [ + "0.0.0", + "0.0.1" + ] + }, + { + "description": "node-semver treats \"0.0.1\" and \"0.0.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "0.0.1", + "0.0.0" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"0.9.9\" before \"1.0.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.0.0", + "0.9.9" + ] + }, + "expected_output": [ + "0.9.9", + "1.0.0" + ] + }, + { + "description": "node-semver treats \"1.0.0\" and \"0.9.9\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.0.0", + "0.9.9" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"0.9.0\" before \"0.10.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "0.10.0", + "0.9.0" + ] + }, + "expected_output": [ + "0.9.0", + "0.10.0" + ] + }, + { + "description": "node-semver treats \"0.10.0\" and \"0.9.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "0.10.0", + "0.9.0" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"0.10.0\" before \"0.99.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "0.99.0", + "0.10.0" + ] + }, + "expected_output": [ + "0.10.0", + "0.99.0" + ] + }, + { + "description": "node-semver treats \"0.99.0\" and \"0.10.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "0.99.0", + "0.10.0" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3\" before \"2.0.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "2.0.0", + "1.2.3" + ] + }, + "expected_output": [ + "1.2.3", + "2.0.0" + ] + }, + { + "description": "node-semver treats \"2.0.0\" and \"1.2.3\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "2.0.0", + "1.2.3" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-asdf\" before \"1.2.3\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3", + "1.2.3-asdf" + ] + }, + "expected_output": [ + "1.2.3-asdf", + "1.2.3" + ] + }, + { + "description": "node-semver treats \"1.2.3\" and \"1.2.3-asdf\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3", + "1.2.3-asdf" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-4\" before \"1.2.3\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3", + "1.2.3-4" + ] + }, + "expected_output": [ + "1.2.3-4", + "1.2.3" + ] + }, + { + "description": "node-semver treats \"1.2.3\" and \"1.2.3-4\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3", + "1.2.3-4" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-4-foo\" before \"1.2.3\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3", + "1.2.3-4-foo" + ] + }, + "expected_output": [ + "1.2.3-4-foo", + "1.2.3" + ] + }, + { + "description": "node-semver treats \"1.2.3\" and \"1.2.3-4-foo\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3", + "1.2.3-4-foo" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-5\" before \"1.2.3-5-foo\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-5-foo", + "1.2.3-5" + ] + }, + "expected_output": [ + "1.2.3-5", + "1.2.3-5-foo" + ] + }, + { + "description": "node-semver treats \"1.2.3-5-foo\" and \"1.2.3-5\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-5-foo", + "1.2.3-5" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-4\" before \"1.2.3-5\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-5", + "1.2.3-4" + ] + }, + "expected_output": [ + "1.2.3-4", + "1.2.3-5" + ] + }, + { + "description": "node-semver treats \"1.2.3-5\" and \"1.2.3-4\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-5", + "1.2.3-4" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-5-Foo\" before \"1.2.3-5-foo\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-5-foo", + "1.2.3-5-Foo" + ] + }, + "expected_output": [ + "1.2.3-5-Foo", + "1.2.3-5-foo" + ] + }, + { + "description": "node-semver treats \"1.2.3-5-foo\" and \"1.2.3-5-Foo\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-5-foo", + "1.2.3-5-Foo" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"2.7.2+asdf\" before \"3.0.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "3.0.0", + "2.7.2+asdf" + ] + }, + "expected_output": [ + "2.7.2+asdf", + "3.0.0" + ] + }, + { + "description": "node-semver treats \"3.0.0\" and \"2.7.2+asdf\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "3.0.0", + "2.7.2+asdf" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-a.5\" before \"1.2.3-a.10\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-a.10", + "1.2.3-a.5" + ] + }, + "expected_output": [ + "1.2.3-a.5", + "1.2.3-a.10" + ] + }, + { + "description": "node-semver treats \"1.2.3-a.10\" and \"1.2.3-a.5\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-a.10", + "1.2.3-a.5" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-a.5\" before \"1.2.3-a.b\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-a.b", + "1.2.3-a.5" + ] + }, + "expected_output": [ + "1.2.3-a.5", + "1.2.3-a.b" + ] + }, + { + "description": "node-semver treats \"1.2.3-a.b\" and \"1.2.3-a.5\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-a.b", + "1.2.3-a.5" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-a\" before \"1.2.3-a.b\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-a.b", + "1.2.3-a" + ] + }, + "expected_output": [ + "1.2.3-a", + "1.2.3-a.b" + ] + }, + { + "description": "node-semver treats \"1.2.3-a.b\" and \"1.2.3-a\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-a.b", + "1.2.3-a" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-a.b.c.5.d.100\" before \"1.2.3-a.b.c.10.d.5\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-a.b.c.10.d.5", + "1.2.3-a.b.c.5.d.100" + ] + }, + "expected_output": [ + "1.2.3-a.b.c.5.d.100", + "1.2.3-a.b.c.10.d.5" + ] + }, + { + "description": "node-semver treats \"1.2.3-a.b.c.10.d.5\" and \"1.2.3-a.b.c.5.d.100\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-a.b.c.10.d.5", + "1.2.3-a.b.c.5.d.100" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-r100\" before \"1.2.3-r2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-r2", + "1.2.3-r100" + ] + }, + "expected_output": [ + "1.2.3-r100", + "1.2.3-r2" + ] + }, + { + "description": "node-semver treats \"1.2.3-r2\" and \"1.2.3-r100\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-r2", + "1.2.3-r100" + ] + }, + "expected_output": false + }, + { + "description": "node-semver orders \"1.2.3-R2\" before \"1.2.3-r100\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-r100", + "1.2.3-R2" + ] + }, + "expected_output": [ + "1.2.3-R2", + "1.2.3-r100" + ] + }, + { + "description": "node-semver treats \"1.2.3-r100\" and \"1.2.3-R2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-r100", + "1.2.3-R2" + ] + }, + "expected_output": false + }, + { + "description": "node-semver treats \"1.2.3-beta+build\" and \"1.2.3-beta+otherbuild\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3-beta+build", + "1.2.3-beta+otherbuild" + ] + }, + "expected_output": true + }, + { + "description": "node-semver treats \"1.2.3+build\" and \"1.2.3+otherbuild\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + "1.2.3+build", + "1.2.3+otherbuild" + ] + }, + "expected_output": true + }, + { + "description": "node-semver treats \" v1.2.3+build\" and \"1.2.3+otherbuild\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "npm", + "versions": [ + " v1.2.3+build", + "1.2.3+otherbuild" + ] + }, + "expected_output": true + } + ] +} diff --git a/testdata/local/tests/pub_version_cmp_test.json b/testdata/local/tests/pub_version_cmp_test.json index f261776..cc9609a 100644 --- a/testdata/local/tests/pub_version_cmp_test.json +++ b/testdata/local/tests/pub_version_cmp_test.json @@ -2,36 +2,530 @@ "$schema": "https://packageurl.org/schemas/vers-test.schema-0.2.json", "tests": [ { - "description": "Pub orders numeric build identifiers numerically.", + "description": "pub_semver orders \"1.0.0-alpha\" before \"1.0.0-alpha.1\".", "test_group": "recommended", "test_type": "comparison", "input": { "input_type": "pub", "versions": [ - "1.2.3+11", - "1.2.3+2" + "1.0.0-alpha.1", + "1.0.0-alpha" ] }, "expected_output": [ - "1.2.3+2", - "1.2.3+11" + "1.0.0-alpha", + "1.0.0-alpha.1" ] }, { - "description": "Pub orders a version without build metadata first.", + "description": "pub_semver treats \"1.0.0-alpha\" and \"1.0.0-alpha.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0-alpha", + "1.0.0-alpha.1" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"1.0.0-alpha.1\" before \"1.0.0-beta.2\".", "test_group": "recommended", "test_type": "comparison", "input": { "input_type": "pub", "versions": [ - "1.2.3+one", - "1.2.3" + "1.0.0-beta.2", + "1.0.0-alpha.1" + ] + }, + "expected_output": [ + "1.0.0-alpha.1", + "1.0.0-beta.2" + ] + }, + { + "description": "pub_semver treats \"1.0.0-alpha.1\" and \"1.0.0-beta.2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0-alpha.1", + "1.0.0-beta.2" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"1.0.0-beta.2\" before \"1.0.0-beta.11\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0-beta.11", + "1.0.0-beta.2" + ] + }, + "expected_output": [ + "1.0.0-beta.2", + "1.0.0-beta.11" + ] + }, + { + "description": "pub_semver treats \"1.0.0-beta.2\" and \"1.0.0-beta.11\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0-beta.2", + "1.0.0-beta.11" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"1.0.0-beta.11\" before \"1.0.0-rc.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0-rc.1", + "1.0.0-beta.11" + ] + }, + "expected_output": [ + "1.0.0-beta.11", + "1.0.0-rc.1" + ] + }, + { + "description": "pub_semver treats \"1.0.0-beta.11\" and \"1.0.0-rc.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0-beta.11", + "1.0.0-rc.1" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"1.0.0-rc.1\" before \"1.0.0-rc.1+build.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0-rc.1+build.1", + "1.0.0-rc.1" + ] + }, + "expected_output": [ + "1.0.0-rc.1", + "1.0.0-rc.1+build.1" + ] + }, + { + "description": "pub_semver treats \"1.0.0-rc.1\" and \"1.0.0-rc.1+build.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0-rc.1", + "1.0.0-rc.1+build.1" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"1.0.0-rc.1+build.1\" before \"1.0.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0", + "1.0.0-rc.1+build.1" ] }, "expected_output": [ - "1.2.3", - "1.2.3+one" + "1.0.0-rc.1+build.1", + "1.0.0" ] + }, + { + "description": "pub_semver treats \"1.0.0-rc.1+build.1\" and \"1.0.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0-rc.1+build.1", + "1.0.0" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"1.0.0\" before \"1.0.0+0.3.7\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0+0.3.7", + "1.0.0" + ] + }, + "expected_output": [ + "1.0.0", + "1.0.0+0.3.7" + ] + }, + { + "description": "pub_semver treats \"1.0.0\" and \"1.0.0+0.3.7\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0", + "1.0.0+0.3.7" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"1.0.0+0.3.7\" before \"1.3.7+build\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "1.3.7+build", + "1.0.0+0.3.7" + ] + }, + "expected_output": [ + "1.0.0+0.3.7", + "1.3.7+build" + ] + }, + { + "description": "pub_semver treats \"1.0.0+0.3.7\" and \"1.3.7+build\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0+0.3.7", + "1.3.7+build" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"1.3.7+build\" before \"1.3.7+build.2.b8f12d7\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "1.3.7+build.2.b8f12d7", + "1.3.7+build" + ] + }, + "expected_output": [ + "1.3.7+build", + "1.3.7+build.2.b8f12d7" + ] + }, + { + "description": "pub_semver treats \"1.3.7+build\" and \"1.3.7+build.2.b8f12d7\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.3.7+build", + "1.3.7+build.2.b8f12d7" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"1.3.7+build.2.b8f12d7\" before \"1.3.7+build.11.e0f985a\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "1.3.7+build.11.e0f985a", + "1.3.7+build.2.b8f12d7" + ] + }, + "expected_output": [ + "1.3.7+build.2.b8f12d7", + "1.3.7+build.11.e0f985a" + ] + }, + { + "description": "pub_semver treats \"1.3.7+build.2.b8f12d7\" and \"1.3.7+build.11.e0f985a\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.3.7+build.2.b8f12d7", + "1.3.7+build.11.e0f985a" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"1.3.7+build.11.e0f985a\" before \"2.0.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "2.0.0", + "1.3.7+build.11.e0f985a" + ] + }, + "expected_output": [ + "1.3.7+build.11.e0f985a", + "2.0.0" + ] + }, + { + "description": "pub_semver treats \"1.3.7+build.11.e0f985a\" and \"2.0.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.3.7+build.11.e0f985a", + "2.0.0" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"2.0.0\" before \"2.1.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "2.1.0", + "2.0.0" + ] + }, + "expected_output": [ + "2.0.0", + "2.1.0" + ] + }, + { + "description": "pub_semver treats \"2.0.0\" and \"2.1.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "2.0.0", + "2.1.0" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"2.1.0\" before \"2.2.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "2.2.0", + "2.1.0" + ] + }, + "expected_output": [ + "2.1.0", + "2.2.0" + ] + }, + { + "description": "pub_semver treats \"2.1.0\" and \"2.2.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "2.1.0", + "2.2.0" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"2.2.0\" before \"2.11.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "2.11.0", + "2.2.0" + ] + }, + "expected_output": [ + "2.2.0", + "2.11.0" + ] + }, + { + "description": "pub_semver treats \"2.2.0\" and \"2.11.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "2.2.0", + "2.11.0" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver orders \"2.11.0\" before \"2.11.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pub", + "versions": [ + "2.11.1", + "2.11.0" + ] + }, + "expected_output": [ + "2.11.0", + "2.11.1" + ] + }, + { + "description": "pub_semver treats \"2.11.0\" and \"2.11.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "2.11.0", + "2.11.1" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver treats \"01.2.3\" and \"1.2.3\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "01.2.3", + "1.2.3" + ] + }, + "expected_output": true + }, + { + "description": "pub_semver treats \"1.02.3\" and \"1.2.3\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.02.3", + "1.2.3" + ] + }, + "expected_output": true + }, + { + "description": "pub_semver treats \"1.2.03\" and \"1.2.3\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.2.03", + "1.2.3" + ] + }, + "expected_output": true + }, + { + "description": "pub_semver treats \"1.2.3-01\" and \"1.2.3-1\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.2.3-01", + "1.2.3-1" + ] + }, + "expected_output": true + }, + { + "description": "pub_semver treats \"1.2.3+01\" and \"1.2.3+1\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.2.3+01", + "1.2.3+1" + ] + }, + "expected_output": true + }, + { + "description": "pub_semver treats \"1.0.0-0xA\" and \"1.0.0-10\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0-0xA", + "1.0.0-10" + ] + }, + "expected_output": false + }, + { + "description": "pub_semver treats \"1.0.0+0xFF\" and \"1.0.0+255\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pub", + "versions": [ + "1.0.0+0xFF", + "1.0.0+255" + ] + }, + "expected_output": false } ] } diff --git a/testdata/local/tests/pypi_version_cmp_test.json b/testdata/local/tests/pypi_version_cmp_test.json new file mode 100644 index 0000000..98a20de --- /dev/null +++ b/testdata/local/tests/pypi_version_cmp_test.json @@ -0,0 +1,2657 @@ +{ + "$schema": "https://packageurl.org/schemas/vers-test.schema-0.2.json", + "tests": [ + { + "description": "packaging orders \"1.0.dev0\" before \"1.0.dev456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.dev456", + "1.0.dev0" + ] + }, + "expected_output": [ + "1.0.dev0", + "1.0.dev456" + ] + }, + { + "description": "packaging treats \"1.0.dev0\" and \"1.0.dev456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.dev0", + "1.0.dev456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.dev456\" before \"1.0.dev456+local\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.dev456+local", + "1.0.dev456" + ] + }, + "expected_output": [ + "1.0.dev456", + "1.0.dev456+local" + ] + }, + { + "description": "packaging treats \"1.0.dev456\" and \"1.0.dev456+local\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.dev456", + "1.0.dev456+local" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.dev456+local\" before \"1.0a0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a0", + "1.0.dev456+local" + ] + }, + "expected_output": [ + "1.0.dev456+local", + "1.0a0" + ] + }, + { + "description": "packaging treats \"1.0.dev456+local\" and \"1.0a0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.dev456+local", + "1.0a0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0a0\" before \"1.0a0.post0.dev0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a0.post0.dev0", + "1.0a0" + ] + }, + "expected_output": [ + "1.0a0", + "1.0a0.post0.dev0" + ] + }, + { + "description": "packaging treats \"1.0a0\" and \"1.0a0.post0.dev0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a0", + "1.0a0.post0.dev0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0a0.post0.dev0\" before \"1.0a0.post0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a0.post0", + "1.0a0.post0.dev0" + ] + }, + "expected_output": [ + "1.0a0.post0.dev0", + "1.0a0.post0" + ] + }, + { + "description": "packaging treats \"1.0a0.post0.dev0\" and \"1.0a0.post0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a0.post0.dev0", + "1.0a0.post0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0a0.post0\" before \"1.0a1.dev1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a1.dev1", + "1.0a0.post0" + ] + }, + "expected_output": [ + "1.0a0.post0", + "1.0a1.dev1" + ] + }, + { + "description": "packaging treats \"1.0a0.post0\" and \"1.0a1.dev1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a0.post0", + "1.0a1.dev1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0a1.dev1\" before \"1.0a1.dev1+local\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a1.dev1+local", + "1.0a1.dev1" + ] + }, + "expected_output": [ + "1.0a1.dev1", + "1.0a1.dev1+local" + ] + }, + { + "description": "packaging treats \"1.0a1.dev1\" and \"1.0a1.dev1+local\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a1.dev1", + "1.0a1.dev1+local" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0a1.dev1+local\" before \"1.0a1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a1", + "1.0a1.dev1+local" + ] + }, + "expected_output": [ + "1.0a1.dev1+local", + "1.0a1" + ] + }, + { + "description": "packaging treats \"1.0a1.dev1+local\" and \"1.0a1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a1.dev1+local", + "1.0a1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0a1\" before \"1.0a1+local\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a1+local", + "1.0a1" + ] + }, + "expected_output": [ + "1.0a1", + "1.0a1+local" + ] + }, + { + "description": "packaging treats \"1.0a1\" and \"1.0a1+local\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a1", + "1.0a1+local" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0a1+local\" before \"1.0b0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b0", + "1.0a1+local" + ] + }, + "expected_output": [ + "1.0a1+local", + "1.0b0" + ] + }, + { + "description": "packaging treats \"1.0a1+local\" and \"1.0b0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0a1+local", + "1.0b0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0b0\" before \"1.0b1.dev456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b1.dev456", + "1.0b0" + ] + }, + "expected_output": [ + "1.0b0", + "1.0b1.dev456" + ] + }, + { + "description": "packaging treats \"1.0b0\" and \"1.0b1.dev456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b0", + "1.0b1.dev456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0b1.dev456\" before \"1.0b2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b2", + "1.0b1.dev456" + ] + }, + "expected_output": [ + "1.0b1.dev456", + "1.0b2" + ] + }, + { + "description": "packaging treats \"1.0b1.dev456\" and \"1.0b2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b1.dev456", + "1.0b2" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0b2\" before \"1.0b2.post345.dev456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b2.post345.dev456", + "1.0b2" + ] + }, + "expected_output": [ + "1.0b2", + "1.0b2.post345.dev456" + ] + }, + { + "description": "packaging treats \"1.0b2\" and \"1.0b2.post345.dev456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b2", + "1.0b2.post345.dev456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0b2.post345.dev456\" before \"1.0b2.post345\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b2.post345", + "1.0b2.post345.dev456" + ] + }, + "expected_output": [ + "1.0b2.post345.dev456", + "1.0b2.post345" + ] + }, + { + "description": "packaging treats \"1.0b2.post345.dev456\" and \"1.0b2.post345\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b2.post345.dev456", + "1.0b2.post345" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0b2.post345\" before \"1.0b2-346\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b2-346", + "1.0b2.post345" + ] + }, + "expected_output": [ + "1.0b2.post345", + "1.0b2-346" + ] + }, + { + "description": "packaging treats \"1.0b2.post345\" and \"1.0b2-346\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b2.post345", + "1.0b2-346" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0b2-346\" before \"1.0rc0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0rc0", + "1.0b2-346" + ] + }, + "expected_output": [ + "1.0b2-346", + "1.0rc0" + ] + }, + { + "description": "packaging treats \"1.0b2-346\" and \"1.0rc0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0b2-346", + "1.0rc0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0rc0\" before \"1.0rc1.dev1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0rc1.dev1", + "1.0rc0" + ] + }, + "expected_output": [ + "1.0rc0", + "1.0rc1.dev1" + ] + }, + { + "description": "packaging treats \"1.0rc0\" and \"1.0rc1.dev1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0rc0", + "1.0rc1.dev1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0rc1.dev1\" before \"1.0c1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0c1", + "1.0rc1.dev1" + ] + }, + "expected_output": [ + "1.0rc1.dev1", + "1.0c1" + ] + }, + { + "description": "packaging treats \"1.0rc1.dev1\" and \"1.0c1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0rc1.dev1", + "1.0c1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0c1\" before \"1.0rc2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0rc2", + "1.0c1" + ] + }, + "expected_output": [ + "1.0c1", + "1.0rc2" + ] + }, + { + "description": "packaging treats \"1.0c1\" and \"1.0rc2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0c1", + "1.0rc2" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0rc2\" before \"1.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0", + "1.0rc2" + ] + }, + "expected_output": [ + "1.0rc2", + "1.0" + ] + }, + { + "description": "packaging treats \"1.0rc2\" and \"1.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0rc2", + "1.0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0\" before \"1.0.post0.dev0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.post0.dev0", + "1.0" + ] + }, + "expected_output": [ + "1.0", + "1.0.post0.dev0" + ] + }, + { + "description": "packaging treats \"1.0\" and \"1.0.post0.dev0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0", + "1.0.post0.dev0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.post0.dev0\" before \"1.0.post0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.post0", + "1.0.post0.dev0" + ] + }, + "expected_output": [ + "1.0.post0.dev0", + "1.0.post0" + ] + }, + { + "description": "packaging treats \"1.0.post0.dev0\" and \"1.0.post0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.post0.dev0", + "1.0.post0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.post0\" before \"1.0.post456.dev34\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.post456.dev34", + "1.0.post0" + ] + }, + "expected_output": [ + "1.0.post0", + "1.0.post456.dev34" + ] + }, + { + "description": "packaging treats \"1.0.post0\" and \"1.0.post456.dev34\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.post0", + "1.0.post456.dev34" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.post456.dev34\" before \"1.0.post456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.post456", + "1.0.post456.dev34" + ] + }, + "expected_output": [ + "1.0.post456.dev34", + "1.0.post456" + ] + }, + { + "description": "packaging treats \"1.0.post456.dev34\" and \"1.0.post456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.post456.dev34", + "1.0.post456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.post456\" before \"1.0.post456+local\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.post456+local", + "1.0.post456" + ] + }, + "expected_output": [ + "1.0.post456", + "1.0.post456+local" + ] + }, + { + "description": "packaging treats \"1.0.post456\" and \"1.0.post456+local\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.post456", + "1.0.post456+local" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.post456+local\" before \"1.0.1.dev1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.1.dev1", + "1.0.post456+local" + ] + }, + "expected_output": [ + "1.0.post456+local", + "1.0.1.dev1" + ] + }, + { + "description": "packaging treats \"1.0.post456+local\" and \"1.0.1.dev1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.post456+local", + "1.0.1.dev1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.1.dev1\" before \"1.0.1a1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.1a1", + "1.0.1.dev1" + ] + }, + "expected_output": [ + "1.0.1.dev1", + "1.0.1a1" + ] + }, + { + "description": "packaging treats \"1.0.1.dev1\" and \"1.0.1a1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.1.dev1", + "1.0.1a1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.1a1\" before \"1.0.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.1", + "1.0.1a1" + ] + }, + "expected_output": [ + "1.0.1a1", + "1.0.1" + ] + }, + { + "description": "packaging treats \"1.0.1a1\" and \"1.0.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.1a1", + "1.0.1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.1\" before \"1.0.1+local\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.1+local", + "1.0.1" + ] + }, + "expected_output": [ + "1.0.1", + "1.0.1+local" + ] + }, + { + "description": "packaging treats \"1.0.1\" and \"1.0.1+local\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.1", + "1.0.1+local" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.1+local\" before \"1.0.1.post1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.1.post1", + "1.0.1+local" + ] + }, + "expected_output": [ + "1.0.1+local", + "1.0.1.post1" + ] + }, + { + "description": "packaging treats \"1.0.1+local\" and \"1.0.1.post1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.1+local", + "1.0.1.post1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.0.1.post1\" before \"1.1.dev1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.1.dev1", + "1.0.1.post1" + ] + }, + "expected_output": [ + "1.0.1.post1", + "1.1.dev1" + ] + }, + { + "description": "packaging treats \"1.0.1.post1\" and \"1.1.dev1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0.1.post1", + "1.1.dev1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.1.dev1\" before \"1.2+a\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+a", + "1.1.dev1" + ] + }, + "expected_output": [ + "1.1.dev1", + "1.2+a" + ] + }, + { + "description": "packaging treats \"1.1.dev1\" and \"1.2+a\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.1.dev1", + "1.2+a" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+a\" before \"1.2+abc\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+abc", + "1.2+a" + ] + }, + "expected_output": [ + "1.2+a", + "1.2+abc" + ] + }, + { + "description": "packaging treats \"1.2+a\" and \"1.2+abc\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+a", + "1.2+abc" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+abc\" before \"1.2+abcdef\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+abcdef", + "1.2+abc" + ] + }, + "expected_output": [ + "1.2+abc", + "1.2+abcdef" + ] + }, + { + "description": "packaging treats \"1.2+abc\" and \"1.2+abcdef\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+abc", + "1.2+abcdef" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+abcdef\" before \"1.2+def\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+def", + "1.2+abcdef" + ] + }, + "expected_output": [ + "1.2+abcdef", + "1.2+def" + ] + }, + { + "description": "packaging treats \"1.2+abcdef\" and \"1.2+def\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+abcdef", + "1.2+def" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+def\" before \"1.2+0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+0", + "1.2+def" + ] + }, + "expected_output": [ + "1.2+def", + "1.2+0" + ] + }, + { + "description": "packaging treats \"1.2+def\" and \"1.2+0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+def", + "1.2+0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+0\" before \"1.2+1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+1", + "1.2+0" + ] + }, + "expected_output": [ + "1.2+0", + "1.2+1" + ] + }, + { + "description": "packaging treats \"1.2+0\" and \"1.2+1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+0", + "1.2+1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+1\" before \"1.2+1.abc\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+1.abc", + "1.2+1" + ] + }, + "expected_output": [ + "1.2+1", + "1.2+1.abc" + ] + }, + { + "description": "packaging treats \"1.2+1\" and \"1.2+1.abc\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+1", + "1.2+1.abc" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+1.abc\" before \"1.2+1.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+1.1", + "1.2+1.abc" + ] + }, + "expected_output": [ + "1.2+1.abc", + "1.2+1.1" + ] + }, + { + "description": "packaging treats \"1.2+1.abc\" and \"1.2+1.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+1.abc", + "1.2+1.1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+1.1\" before \"1.2+1.1.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+1.1.0", + "1.2+1.1" + ] + }, + "expected_output": [ + "1.2+1.1", + "1.2+1.1.0" + ] + }, + { + "description": "packaging treats \"1.2+1.1\" and \"1.2+1.1.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+1.1", + "1.2+1.1.0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+1.1.0\" before \"1.2+2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+2", + "1.2+1.1.0" + ] + }, + "expected_output": [ + "1.2+1.1.0", + "1.2+2" + ] + }, + { + "description": "packaging treats \"1.2+1.1.0\" and \"1.2+2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+1.1.0", + "1.2+2" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+2\" before \"1.2+123\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+123", + "1.2+2" + ] + }, + "expected_output": [ + "1.2+2", + "1.2+123" + ] + }, + { + "description": "packaging treats \"1.2+2\" and \"1.2+123\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+2", + "1.2+123" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+123\" before \"1.2+123456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+123456", + "1.2+123" + ] + }, + "expected_output": [ + "1.2+123", + "1.2+123456" + ] + }, + { + "description": "packaging treats \"1.2+123\" and \"1.2+123456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+123", + "1.2+123456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2+123456\" before \"1.2.r32+123456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2.r32+123456", + "1.2+123456" + ] + }, + "expected_output": [ + "1.2+123456", + "1.2.r32+123456" + ] + }, + { + "description": "packaging treats \"1.2+123456\" and \"1.2.r32+123456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2+123456", + "1.2.r32+123456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2.r32+123456\" before \"1.2.rev33+123456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1.2.rev33+123456", + "1.2.r32+123456" + ] + }, + "expected_output": [ + "1.2.r32+123456", + "1.2.rev33+123456" + ] + }, + { + "description": "packaging treats \"1.2.r32+123456\" and \"1.2.rev33+123456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2.r32+123456", + "1.2.rev33+123456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1.2.rev33+123456\" before \"1!1.0.dev0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.dev0", + "1.2.rev33+123456" + ] + }, + "expected_output": [ + "1.2.rev33+123456", + "1!1.0.dev0" + ] + }, + { + "description": "packaging treats \"1.2.rev33+123456\" and \"1!1.0.dev0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.2.rev33+123456", + "1!1.0.dev0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.dev0\" before \"1!1.0.dev456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.dev456", + "1!1.0.dev0" + ] + }, + "expected_output": [ + "1!1.0.dev0", + "1!1.0.dev456" + ] + }, + { + "description": "packaging treats \"1!1.0.dev0\" and \"1!1.0.dev456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.dev0", + "1!1.0.dev456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.dev456\" before \"1!1.0.dev456+local\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.dev456+local", + "1!1.0.dev456" + ] + }, + "expected_output": [ + "1!1.0.dev456", + "1!1.0.dev456+local" + ] + }, + { + "description": "packaging treats \"1!1.0.dev456\" and \"1!1.0.dev456+local\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.dev456", + "1!1.0.dev456+local" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.dev456+local\" before \"1!1.0a0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a0", + "1!1.0.dev456+local" + ] + }, + "expected_output": [ + "1!1.0.dev456+local", + "1!1.0a0" + ] + }, + { + "description": "packaging treats \"1!1.0.dev456+local\" and \"1!1.0a0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.dev456+local", + "1!1.0a0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0a0\" before \"1!1.0a0.post0.dev0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a0.post0.dev0", + "1!1.0a0" + ] + }, + "expected_output": [ + "1!1.0a0", + "1!1.0a0.post0.dev0" + ] + }, + { + "description": "packaging treats \"1!1.0a0\" and \"1!1.0a0.post0.dev0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a0", + "1!1.0a0.post0.dev0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0a0.post0.dev0\" before \"1!1.0a0.post0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a0.post0", + "1!1.0a0.post0.dev0" + ] + }, + "expected_output": [ + "1!1.0a0.post0.dev0", + "1!1.0a0.post0" + ] + }, + { + "description": "packaging treats \"1!1.0a0.post0.dev0\" and \"1!1.0a0.post0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a0.post0.dev0", + "1!1.0a0.post0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0a0.post0\" before \"1!1.0a1.dev1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a1.dev1", + "1!1.0a0.post0" + ] + }, + "expected_output": [ + "1!1.0a0.post0", + "1!1.0a1.dev1" + ] + }, + { + "description": "packaging treats \"1!1.0a0.post0\" and \"1!1.0a1.dev1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a0.post0", + "1!1.0a1.dev1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0a1.dev1\" before \"1!1.0a1.dev1+local\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a1.dev1+local", + "1!1.0a1.dev1" + ] + }, + "expected_output": [ + "1!1.0a1.dev1", + "1!1.0a1.dev1+local" + ] + }, + { + "description": "packaging treats \"1!1.0a1.dev1\" and \"1!1.0a1.dev1+local\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a1.dev1", + "1!1.0a1.dev1+local" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0a1.dev1+local\" before \"1!1.0a1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a1", + "1!1.0a1.dev1+local" + ] + }, + "expected_output": [ + "1!1.0a1.dev1+local", + "1!1.0a1" + ] + }, + { + "description": "packaging treats \"1!1.0a1.dev1+local\" and \"1!1.0a1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a1.dev1+local", + "1!1.0a1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0a1\" before \"1!1.0a1+local\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a1+local", + "1!1.0a1" + ] + }, + "expected_output": [ + "1!1.0a1", + "1!1.0a1+local" + ] + }, + { + "description": "packaging treats \"1!1.0a1\" and \"1!1.0a1+local\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a1", + "1!1.0a1+local" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0a1+local\" before \"1!1.0b0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b0", + "1!1.0a1+local" + ] + }, + "expected_output": [ + "1!1.0a1+local", + "1!1.0b0" + ] + }, + { + "description": "packaging treats \"1!1.0a1+local\" and \"1!1.0b0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0a1+local", + "1!1.0b0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0b0\" before \"1!1.0b1.dev456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b1.dev456", + "1!1.0b0" + ] + }, + "expected_output": [ + "1!1.0b0", + "1!1.0b1.dev456" + ] + }, + { + "description": "packaging treats \"1!1.0b0\" and \"1!1.0b1.dev456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b0", + "1!1.0b1.dev456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0b1.dev456\" before \"1!1.0b2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b2", + "1!1.0b1.dev456" + ] + }, + "expected_output": [ + "1!1.0b1.dev456", + "1!1.0b2" + ] + }, + { + "description": "packaging treats \"1!1.0b1.dev456\" and \"1!1.0b2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b1.dev456", + "1!1.0b2" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0b2\" before \"1!1.0b2.post345.dev456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b2.post345.dev456", + "1!1.0b2" + ] + }, + "expected_output": [ + "1!1.0b2", + "1!1.0b2.post345.dev456" + ] + }, + { + "description": "packaging treats \"1!1.0b2\" and \"1!1.0b2.post345.dev456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b2", + "1!1.0b2.post345.dev456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0b2.post345.dev456\" before \"1!1.0b2.post345\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b2.post345", + "1!1.0b2.post345.dev456" + ] + }, + "expected_output": [ + "1!1.0b2.post345.dev456", + "1!1.0b2.post345" + ] + }, + { + "description": "packaging treats \"1!1.0b2.post345.dev456\" and \"1!1.0b2.post345\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b2.post345.dev456", + "1!1.0b2.post345" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0b2.post345\" before \"1!1.0b2-346\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b2-346", + "1!1.0b2.post345" + ] + }, + "expected_output": [ + "1!1.0b2.post345", + "1!1.0b2-346" + ] + }, + { + "description": "packaging treats \"1!1.0b2.post345\" and \"1!1.0b2-346\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b2.post345", + "1!1.0b2-346" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0b2-346\" before \"1!1.0rc0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0rc0", + "1!1.0b2-346" + ] + }, + "expected_output": [ + "1!1.0b2-346", + "1!1.0rc0" + ] + }, + { + "description": "packaging treats \"1!1.0b2-346\" and \"1!1.0rc0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0b2-346", + "1!1.0rc0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0rc0\" before \"1!1.0rc1.dev1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0rc1.dev1", + "1!1.0rc0" + ] + }, + "expected_output": [ + "1!1.0rc0", + "1!1.0rc1.dev1" + ] + }, + { + "description": "packaging treats \"1!1.0rc0\" and \"1!1.0rc1.dev1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0rc0", + "1!1.0rc1.dev1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0rc1.dev1\" before \"1!1.0c1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0c1", + "1!1.0rc1.dev1" + ] + }, + "expected_output": [ + "1!1.0rc1.dev1", + "1!1.0c1" + ] + }, + { + "description": "packaging treats \"1!1.0rc1.dev1\" and \"1!1.0c1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0rc1.dev1", + "1!1.0c1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0c1\" before \"1!1.0rc2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0rc2", + "1!1.0c1" + ] + }, + "expected_output": [ + "1!1.0c1", + "1!1.0rc2" + ] + }, + { + "description": "packaging treats \"1!1.0c1\" and \"1!1.0rc2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0c1", + "1!1.0rc2" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0rc2\" before \"1!1.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0", + "1!1.0rc2" + ] + }, + "expected_output": [ + "1!1.0rc2", + "1!1.0" + ] + }, + { + "description": "packaging treats \"1!1.0rc2\" and \"1!1.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0rc2", + "1!1.0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0\" before \"1!1.0.post0.dev0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.post0.dev0", + "1!1.0" + ] + }, + "expected_output": [ + "1!1.0", + "1!1.0.post0.dev0" + ] + }, + { + "description": "packaging treats \"1!1.0\" and \"1!1.0.post0.dev0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0", + "1!1.0.post0.dev0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.post0.dev0\" before \"1!1.0.post0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.post0", + "1!1.0.post0.dev0" + ] + }, + "expected_output": [ + "1!1.0.post0.dev0", + "1!1.0.post0" + ] + }, + { + "description": "packaging treats \"1!1.0.post0.dev0\" and \"1!1.0.post0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.post0.dev0", + "1!1.0.post0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.post0\" before \"1!1.0.post456.dev34\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.post456.dev34", + "1!1.0.post0" + ] + }, + "expected_output": [ + "1!1.0.post0", + "1!1.0.post456.dev34" + ] + }, + { + "description": "packaging treats \"1!1.0.post0\" and \"1!1.0.post456.dev34\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.post0", + "1!1.0.post456.dev34" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.post456.dev34\" before \"1!1.0.post456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.post456", + "1!1.0.post456.dev34" + ] + }, + "expected_output": [ + "1!1.0.post456.dev34", + "1!1.0.post456" + ] + }, + { + "description": "packaging treats \"1!1.0.post456.dev34\" and \"1!1.0.post456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.post456.dev34", + "1!1.0.post456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.post456\" before \"1!1.0.post456+local\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.post456+local", + "1!1.0.post456" + ] + }, + "expected_output": [ + "1!1.0.post456", + "1!1.0.post456+local" + ] + }, + { + "description": "packaging treats \"1!1.0.post456\" and \"1!1.0.post456+local\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.post456", + "1!1.0.post456+local" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.post456+local\" before \"1!1.0.1.dev1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.1.dev1", + "1!1.0.post456+local" + ] + }, + "expected_output": [ + "1!1.0.post456+local", + "1!1.0.1.dev1" + ] + }, + { + "description": "packaging treats \"1!1.0.post456+local\" and \"1!1.0.1.dev1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.post456+local", + "1!1.0.1.dev1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.1.dev1\" before \"1!1.0.1a1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.1a1", + "1!1.0.1.dev1" + ] + }, + "expected_output": [ + "1!1.0.1.dev1", + "1!1.0.1a1" + ] + }, + { + "description": "packaging treats \"1!1.0.1.dev1\" and \"1!1.0.1a1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.1.dev1", + "1!1.0.1a1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.1a1\" before \"1!1.0.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.1", + "1!1.0.1a1" + ] + }, + "expected_output": [ + "1!1.0.1a1", + "1!1.0.1" + ] + }, + { + "description": "packaging treats \"1!1.0.1a1\" and \"1!1.0.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.1a1", + "1!1.0.1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.1\" before \"1!1.0.1+local\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.1+local", + "1!1.0.1" + ] + }, + "expected_output": [ + "1!1.0.1", + "1!1.0.1+local" + ] + }, + { + "description": "packaging treats \"1!1.0.1\" and \"1!1.0.1+local\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.1", + "1!1.0.1+local" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.1+local\" before \"1!1.0.1.post1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.1.post1", + "1!1.0.1+local" + ] + }, + "expected_output": [ + "1!1.0.1+local", + "1!1.0.1.post1" + ] + }, + { + "description": "packaging treats \"1!1.0.1+local\" and \"1!1.0.1.post1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.1+local", + "1!1.0.1.post1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.0.1.post1\" before \"1!1.1.dev1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.1.dev1", + "1!1.0.1.post1" + ] + }, + "expected_output": [ + "1!1.0.1.post1", + "1!1.1.dev1" + ] + }, + { + "description": "packaging treats \"1!1.0.1.post1\" and \"1!1.1.dev1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.0.1.post1", + "1!1.1.dev1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.1.dev1\" before \"1!1.2+a\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+a", + "1!1.1.dev1" + ] + }, + "expected_output": [ + "1!1.1.dev1", + "1!1.2+a" + ] + }, + { + "description": "packaging treats \"1!1.1.dev1\" and \"1!1.2+a\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.1.dev1", + "1!1.2+a" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+a\" before \"1!1.2+abc\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+abc", + "1!1.2+a" + ] + }, + "expected_output": [ + "1!1.2+a", + "1!1.2+abc" + ] + }, + { + "description": "packaging treats \"1!1.2+a\" and \"1!1.2+abc\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+a", + "1!1.2+abc" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+abc\" before \"1!1.2+abcdef\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+abcdef", + "1!1.2+abc" + ] + }, + "expected_output": [ + "1!1.2+abc", + "1!1.2+abcdef" + ] + }, + { + "description": "packaging treats \"1!1.2+abc\" and \"1!1.2+abcdef\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+abc", + "1!1.2+abcdef" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+abcdef\" before \"1!1.2+def\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+def", + "1!1.2+abcdef" + ] + }, + "expected_output": [ + "1!1.2+abcdef", + "1!1.2+def" + ] + }, + { + "description": "packaging treats \"1!1.2+abcdef\" and \"1!1.2+def\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+abcdef", + "1!1.2+def" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+def\" before \"1!1.2+0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+0", + "1!1.2+def" + ] + }, + "expected_output": [ + "1!1.2+def", + "1!1.2+0" + ] + }, + { + "description": "packaging treats \"1!1.2+def\" and \"1!1.2+0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+def", + "1!1.2+0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+0\" before \"1!1.2+1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+1", + "1!1.2+0" + ] + }, + "expected_output": [ + "1!1.2+0", + "1!1.2+1" + ] + }, + { + "description": "packaging treats \"1!1.2+0\" and \"1!1.2+1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+0", + "1!1.2+1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+1\" before \"1!1.2+1.abc\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+1.abc", + "1!1.2+1" + ] + }, + "expected_output": [ + "1!1.2+1", + "1!1.2+1.abc" + ] + }, + { + "description": "packaging treats \"1!1.2+1\" and \"1!1.2+1.abc\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+1", + "1!1.2+1.abc" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+1.abc\" before \"1!1.2+1.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+1.1", + "1!1.2+1.abc" + ] + }, + "expected_output": [ + "1!1.2+1.abc", + "1!1.2+1.1" + ] + }, + { + "description": "packaging treats \"1!1.2+1.abc\" and \"1!1.2+1.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+1.abc", + "1!1.2+1.1" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+1.1\" before \"1!1.2+1.1.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+1.1.0", + "1!1.2+1.1" + ] + }, + "expected_output": [ + "1!1.2+1.1", + "1!1.2+1.1.0" + ] + }, + { + "description": "packaging treats \"1!1.2+1.1\" and \"1!1.2+1.1.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+1.1", + "1!1.2+1.1.0" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+1.1.0\" before \"1!1.2+2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+2", + "1!1.2+1.1.0" + ] + }, + "expected_output": [ + "1!1.2+1.1.0", + "1!1.2+2" + ] + }, + { + "description": "packaging treats \"1!1.2+1.1.0\" and \"1!1.2+2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+1.1.0", + "1!1.2+2" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+2\" before \"1!1.2+123\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+123", + "1!1.2+2" + ] + }, + "expected_output": [ + "1!1.2+2", + "1!1.2+123" + ] + }, + { + "description": "packaging treats \"1!1.2+2\" and \"1!1.2+123\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+2", + "1!1.2+123" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+123\" before \"1!1.2+123456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+123456", + "1!1.2+123" + ] + }, + "expected_output": [ + "1!1.2+123", + "1!1.2+123456" + ] + }, + { + "description": "packaging treats \"1!1.2+123\" and \"1!1.2+123456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+123", + "1!1.2+123456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2+123456\" before \"1!1.2.r32+123456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2.r32+123456", + "1!1.2+123456" + ] + }, + "expected_output": [ + "1!1.2+123456", + "1!1.2.r32+123456" + ] + }, + { + "description": "packaging treats \"1!1.2+123456\" and \"1!1.2.r32+123456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2+123456", + "1!1.2.r32+123456" + ] + }, + "expected_output": false + }, + { + "description": "packaging orders \"1!1.2.r32+123456\" before \"1!1.2.rev33+123456\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2.rev33+123456", + "1!1.2.r32+123456" + ] + }, + "expected_output": [ + "1!1.2.r32+123456", + "1!1.2.rev33+123456" + ] + }, + { + "description": "packaging treats \"1!1.2.r32+123456\" and \"1!1.2.rev33+123456\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1!1.2.r32+123456", + "1!1.2.rev33+123456" + ] + }, + "expected_output": false + }, + { + "description": "packaging treats \"1.0rc1\" and \"1.0c1\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "pypi", + "versions": [ + "1.0rc1", + "1.0c1" + ] + }, + "expected_output": true + } + ] +} diff --git a/testdata/local/tests/rpm_version_cmp_test.json b/testdata/local/tests/rpm_version_cmp_test.json new file mode 100644 index 0000000..6ff0b0a --- /dev/null +++ b/testdata/local/tests/rpm_version_cmp_test.json @@ -0,0 +1,924 @@ +{ + "$schema": "https://packageurl.org/schemas/vers-test.schema-0.2.json", + "tests": [ + { + "description": "RPM orders \"1.0\" before \"2.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "2.0", + "1.0" + ] + }, + "expected_output": [ + "1.0", + "2.0" + ] + }, + { + "description": "RPM treats \"1.0\" and \"2.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0", + "2.0" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"2.0\" before \"2.0.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "2.0.1", + "2.0" + ] + }, + "expected_output": [ + "2.0", + "2.0.1" + ] + }, + { + "description": "RPM treats \"2.0\" and \"2.0.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "2.0", + "2.0.1" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"2.0.1\" before \"2.0.1a\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "2.0.1a", + "2.0.1" + ] + }, + "expected_output": [ + "2.0.1", + "2.0.1a" + ] + }, + { + "description": "RPM treats \"2.0.1a\" and \"2.0.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "2.0.1a", + "2.0.1" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"5.5p1\" before \"5.5p2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "5.5p2", + "5.5p1" + ] + }, + "expected_output": [ + "5.5p1", + "5.5p2" + ] + }, + { + "description": "RPM treats \"5.5p1\" and \"5.5p2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "5.5p1", + "5.5p2" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"5.5p1\" before \"5.5p10\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "5.5p10", + "5.5p1" + ] + }, + "expected_output": [ + "5.5p1", + "5.5p10" + ] + }, + { + "description": "RPM treats \"5.5p1\" and \"5.5p10\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "5.5p1", + "5.5p10" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"10xyz\" before \"10.1xyz\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "10.1xyz", + "10xyz" + ] + }, + "expected_output": [ + "10xyz", + "10.1xyz" + ] + }, + { + "description": "RPM treats \"10xyz\" and \"10.1xyz\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "10xyz", + "10.1xyz" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"xyz10\" before \"xyz10.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "xyz10.1", + "xyz10" + ] + }, + "expected_output": [ + "xyz10", + "xyz10.1" + ] + }, + { + "description": "RPM treats \"xyz10\" and \"xyz10.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "xyz10", + "xyz10.1" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"xyz.4\" before \"8\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "8", + "xyz.4" + ] + }, + "expected_output": [ + "xyz.4", + "8" + ] + }, + { + "description": "RPM treats \"xyz.4\" and \"8\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "xyz.4", + "8" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"xyz.4\" before \"2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "2", + "xyz.4" + ] + }, + "expected_output": [ + "xyz.4", + "2" + ] + }, + { + "description": "RPM treats \"xyz.4\" and \"2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "xyz.4", + "2" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"5.5p2\" before \"5.6p1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "5.6p1", + "5.5p2" + ] + }, + "expected_output": [ + "5.5p2", + "5.6p1" + ] + }, + { + "description": "RPM treats \"5.5p2\" and \"5.6p1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "5.5p2", + "5.6p1" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"5.6p1\" before \"6.5p1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "6.5p1", + "5.6p1" + ] + }, + "expected_output": [ + "5.6p1", + "6.5p1" + ] + }, + { + "description": "RPM treats \"5.6p1\" and \"6.5p1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "5.6p1", + "6.5p1" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"6.0\" before \"6.0.rc1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "6.0.rc1", + "6.0" + ] + }, + "expected_output": [ + "6.0", + "6.0.rc1" + ] + }, + { + "description": "RPM treats \"6.0.rc1\" and \"6.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "6.0.rc1", + "6.0" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"10a1\" before \"10b2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "10b2", + "10a1" + ] + }, + "expected_output": [ + "10a1", + "10b2" + ] + }, + { + "description": "RPM treats \"10b2\" and \"10a1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "10b2", + "10a1" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"10a2\" before \"10b2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "10b2", + "10a2" + ] + }, + "expected_output": [ + "10a2", + "10b2" + ] + }, + { + "description": "RPM treats \"10a2\" and \"10b2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "10a2", + "10b2" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"1.0a\" before \"1.0aa\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.0aa", + "1.0a" + ] + }, + "expected_output": [ + "1.0a", + "1.0aa" + ] + }, + { + "description": "RPM treats \"1.0a\" and \"1.0aa\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0a", + "1.0aa" + ] + }, + "expected_output": false + }, + { + "description": "RPM treats \"10.0001\" and \"10.1\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "10.0001", + "10.1" + ] + }, + "expected_output": true + }, + { + "description": "RPM orders \"10.0001\" before \"10.0039\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "10.0039", + "10.0001" + ] + }, + "expected_output": [ + "10.0001", + "10.0039" + ] + }, + { + "description": "RPM treats \"10.0001\" and \"10.0039\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "10.0001", + "10.0039" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"4.999.9\" before \"5.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "5.0", + "4.999.9" + ] + }, + "expected_output": [ + "4.999.9", + "5.0" + ] + }, + { + "description": "RPM treats \"4.999.9\" and \"5.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "4.999.9", + "5.0" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"20101121\" before \"20101122\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "20101122", + "20101121" + ] + }, + "expected_output": [ + "20101121", + "20101122" + ] + }, + { + "description": "RPM treats \"20101121\" and \"20101122\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "20101121", + "20101122" + ] + }, + "expected_output": false + }, + { + "description": "RPM treats \"2.0\" and \"2_0\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "2.0", + "2_0" + ] + }, + "expected_output": true + }, + { + "description": "RPM treats \"a+\" and \"a_\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "a+", + "a_" + ] + }, + "expected_output": true + }, + { + "description": "RPM treats \"+a\" and \"_a\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "+a", + "_a" + ] + }, + "expected_output": true + }, + { + "description": "RPM treats \"_+\" and \"+_\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "_+", + "+_" + ] + }, + "expected_output": true + }, + { + "description": "RPM treats \"+\" and \"_\" as equal.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "+", + "_" + ] + }, + "expected_output": true + }, + { + "description": "RPM orders \"1.0~rc1\" before \"1.0\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.0", + "1.0~rc1" + ] + }, + "expected_output": [ + "1.0~rc1", + "1.0" + ] + }, + { + "description": "RPM treats \"1.0~rc1\" and \"1.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0~rc1", + "1.0" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"1.0~rc1\" before \"1.0~rc2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.0~rc2", + "1.0~rc1" + ] + }, + "expected_output": [ + "1.0~rc1", + "1.0~rc2" + ] + }, + { + "description": "RPM treats \"1.0~rc1\" and \"1.0~rc2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0~rc1", + "1.0~rc2" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"1.0~rc1~git123\" before \"1.0~rc1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.0~rc1", + "1.0~rc1~git123" + ] + }, + "expected_output": [ + "1.0~rc1~git123", + "1.0~rc1" + ] + }, + { + "description": "RPM treats \"1.0~rc1~git123\" and \"1.0~rc1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0~rc1~git123", + "1.0~rc1" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"1.0\" before \"1.0^\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^", + "1.0" + ] + }, + "expected_output": [ + "1.0", + "1.0^" + ] + }, + { + "description": "RPM treats \"1.0^\" and \"1.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^", + "1.0" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"1.0\" before \"1.0^git1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^git1", + "1.0" + ] + }, + "expected_output": [ + "1.0", + "1.0^git1" + ] + }, + { + "description": "RPM treats \"1.0^git1\" and \"1.0\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^git1", + "1.0" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"1.0^git1\" before \"1.0^git2\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^git2", + "1.0^git1" + ] + }, + "expected_output": [ + "1.0^git1", + "1.0^git2" + ] + }, + { + "description": "RPM treats \"1.0^git1\" and \"1.0^git2\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^git1", + "1.0^git2" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"1.0^git1\" before \"1.01\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.01", + "1.0^git1" + ] + }, + "expected_output": [ + "1.0^git1", + "1.01" + ] + }, + { + "description": "RPM treats \"1.0^git1\" and \"1.01\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^git1", + "1.01" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"1.0^20160101\" before \"1.0.1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.0.1", + "1.0^20160101" + ] + }, + "expected_output": [ + "1.0^20160101", + "1.0.1" + ] + }, + { + "description": "RPM treats \"1.0^20160101\" and \"1.0.1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^20160101", + "1.0.1" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"1.0^20160101^git1\" before \"1.0^20160102\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^20160102", + "1.0^20160101^git1" + ] + }, + "expected_output": [ + "1.0^20160101^git1", + "1.0^20160102" + ] + }, + { + "description": "RPM treats \"1.0^20160102\" and \"1.0^20160101^git1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^20160102", + "1.0^20160101^git1" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"1.0~rc1\" before \"1.0~rc1^git1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.0~rc1^git1", + "1.0~rc1" + ] + }, + "expected_output": [ + "1.0~rc1", + "1.0~rc1^git1" + ] + }, + { + "description": "RPM treats \"1.0~rc1^git1\" and \"1.0~rc1\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0~rc1^git1", + "1.0~rc1" + ] + }, + "expected_output": false + }, + { + "description": "RPM orders \"1.0^git1~pre\" before \"1.0^git1\".", + "test_group": "recommended", + "test_type": "comparison", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^git1", + "1.0^git1~pre" + ] + }, + "expected_output": [ + "1.0^git1~pre", + "1.0^git1" + ] + }, + { + "description": "RPM treats \"1.0^git1\" and \"1.0^git1~pre\" as different.", + "test_group": "recommended", + "test_type": "equality", + "input": { + "input_type": "rpm", + "versions": [ + "1.0^git1", + "1.0^git1~pre" + ] + }, + "expected_output": false + } + ] +} diff --git a/tools/harvest/extract.go b/tools/harvest/extract.go new file mode 100644 index 0000000..cad7c22 --- /dev/null +++ b/tools/harvest/extract.go @@ -0,0 +1,252 @@ +package main + +import ( + "fmt" + "regexp" + "strconv" + "strings" +) + +const minimumComparisonVersions = 2 + +var quotedValue = regexp.MustCompile(`['"]([^'"]+)['"]`) + +func extractNodeSemver(files map[string]string) ([]comparison, error) { + var items []comparison + row := regexp.MustCompile(`^\s*\[\s*'([^']*)'\s*,\s*'([^']*)'(?:\s*,\s*(.*?))?\s*\],?\s*$`) + for _, filename := range []string{"test/fixtures/comparisons.js", "test/fixtures/equality.js"} { + for _, line := range strings.Split(files[filename], "\n") { + match := row.FindStringSubmatch(line) + if match == nil || strings.Contains(match[3], "true") { + continue + } + result := 0 + if strings.Contains(filename, "comparisons") { + result = 1 + } + items = append(items, comparison{left: match[1], right: match[2], result: result}) + } + } + return requireComparisons(items) +} + +func extractPyPI(files map[string]string) ([]comparison, error) { + content := files["tests/test_version.py"] + versions, err := quotedListAfter(content, "VERSIONS = [") + if err != nil { + return nil, err + } + items := orderedComparisons(versions) + equality := regexp.MustCompile(`Version\("([^"]+)"\)\s*==\s*Version\("([^"]+)"\)`) + for _, match := range equality.FindAllStringSubmatch(content, -1) { + items = append(items, comparison{left: match[1], right: match[2]}) + } + return requireComparisons(items) +} + +func extractRubyGems(files map[string]string) ([]comparison, error) { + content := files["test/rubygems/test_gem_version.rb"] + spaceship := regexp.MustCompile(`assert_equal\(\s*(-?1|0),\s*v\("([^"]*)"\)\s*<=>\s*v\("([^"]*)"\)\)`) + items := make([]comparison, 0) + for _, match := range spaceship.FindAllStringSubmatch(content, -1) { + result, _ := strconv.Atoi(match[1]) + items = append(items, comparison{left: match[2], right: match[3], result: result}) + } + lessThan := regexp.MustCompile(`assert_less_than\s+v\("([^"]*)"\),\s*v\("([^"]*)"\)`) + for _, match := range lessThan.FindAllStringSubmatch(content, -1) { + items = append(items, comparison{left: match[1], right: match[2], result: -1}) + } + return requireComparisons(items) +} + +func extractComposer(files map[string]string) ([]comparison, error) { + content := files["tests/ComparatorTest.php"] + row := regexp.MustCompile(`array\('([^']*)',\s*'([<>=!]+)',\s*'([^']*)',\s*(true|false)\)`) + items := make([]comparison, 0) + for _, match := range row.FindAllStringSubmatch(content, -1) { + if match[4] == "false" { + if match[2] == "==" || match[2] == "=" { + items = append(items, comparison{left: match[1], right: match[3], differentOnly: true}) + } + continue + } + result, ok := strictOperatorResult(match[2]) + if ok { + items = append(items, comparison{left: match[1], right: match[3], result: result}) + } + } + for _, provider := range []struct { + name string + result int + }{{"greaterThanProvider", 1}, {"lessThanProvider", -1}, {"equalToProvider", 0}} { + block := functionBlock(content, "function "+provider.name+"()") + providerRow := regexp.MustCompile(`array\('([^']*)',\s*'([^']*)',\s*(true|false)\)`) + for _, match := range providerRow.FindAllStringSubmatch(block, -1) { + if match[3] == "false" { + if provider.name == "equalToProvider" { + items = append(items, comparison{left: match[1], right: match[2], differentOnly: true}) + } + continue + } + items = append(items, comparison{left: match[1], right: match[2], result: provider.result}) + } + } + return requireComparisons(items) +} + +func extractPub(files map[string]string) ([]comparison, error) { + content := files["pkgs/pub_semver/test/version_test.dart"] + groupStart := strings.Index(content, "group('comparison'") + if groupStart < 0 { + return nil, fmt.Errorf("comparison group not found") + } + comparisonGroup := content[groupStart:] + versions, err := quotedListAfter(comparisonGroup, "var versions = [") + if err != nil { + return nil, err + } + items := orderedComparisons(versions) + equalityBlock := functionBlock(comparisonGroup, "test('equality'") + equality := regexp.MustCompile(`(?s)Version\.parse\('([^']+)'\).*?equals\(Version\.parse\('([^']+)'\)\)`) + for _, match := range equality.FindAllStringSubmatch(equalityBlock, -1) { + if strings.Contains(match[0], "isNot") { + items = append(items, comparison{left: match[1], right: match[2], differentOnly: true}) + } else { + items = append(items, comparison{left: match[1], right: match[2]}) + } + } + return requireComparisons(items) +} + +func extractCargo(files map[string]string) ([]comparison, error) { + content := files["tests/test_version.rs"] + versions, err := quotedListAfter(content, "fn test_spec_order()") + if err != nil { + return nil, err + } + items := orderedComparisons(versions) + lessThan := regexp.MustCompile(`assert!\(version\("([^"]+)"\) < version\("([^"]+)"\)\);`) + for _, match := range lessThan.FindAllStringSubmatch(content, -1) { + items = append(items, comparison{left: match[1], right: match[2], result: -1}) + } + notEqual := regexp.MustCompile(`assert_ne!\(version\("([^"]+)"\), version\("([^"]+)"\)\);`) + for _, match := range notEqual.FindAllStringSubmatch(content, -1) { + items = append(items, comparison{left: match[1], right: match[2], differentOnly: true}) + } + return requireComparisons(items) +} + +func extractDpkg(files map[string]string) ([]comparison, error) { + content := files["lib/dpkg/t/t-version.c"] + assignment := `DPKG_VERSION_OBJECT\((\d+),\s*"([^"]*)",\s*"([^"]*)"\)` + pattern := regexp.MustCompile(`(?s)a = ` + assignment + `;\s*b = ` + assignment + `;\s*test_pass\(dpkg_version_compare\(&a, &b\)\s*(==|<|>)\s*0\);`) + items := make([]comparison, 0) + for _, match := range pattern.FindAllStringSubmatch(content, -1) { + left := debianVersion(match[1], match[2], match[3]) + right := debianVersion(match[4], match[5], match[6]) + result, _ := strictOperatorResult(match[7]) + items = append(items, comparison{left: left, right: right, result: result}) + } + return requireComparisons(items) +} + +func extractRPM(files map[string]string) ([]comparison, error) { + content := files["tests/rpmvercmp.at"] + row := regexp.MustCompile(`(?m)^RPMVERCMP\(([^,]*),\s*([^,]*),\s*(-?1|0)\)$`) + items := make([]comparison, 0) + for _, match := range row.FindAllStringSubmatch(content, -1) { + result, _ := strconv.Atoi(match[3]) + items = append(items, comparison{left: strings.TrimSpace(match[1]), right: strings.TrimSpace(match[2]), result: result}) + } + return requireComparisons(items) +} + +func extractGo(files map[string]string) ([]comparison, error) { + content := files["semver/semver_test.go"] + start := strings.Index(content, "var tests = []struct") + if start < 0 { + return nil, fmt.Errorf("tests table not found") + } + end := strings.Index(content[start:], "\n}\n") + if end < 0 { + return nil, fmt.Errorf("tests table not found") + } + table := content[start : start+end] + row := regexp.MustCompile(`\{"([^"]*)",\s*"([^"]*)"\}`) + matches := row.FindAllStringSubmatch(table, -1) + items := make([]comparison, 0, len(matches)) + for index := 1; index < len(matches); index++ { + result := -1 + if matches[index-1][2] == matches[index][2] { + result = 0 + } + items = append(items, comparison{left: matches[index-1][1], right: matches[index][1], result: result}) + } + return requireComparisons(items) +} + +func quotedListAfter(content, marker string) ([]string, error) { + start := strings.Index(content, marker) + if start < 0 { + return nil, fmt.Errorf("marker %q not found", marker) + } + start += len(marker) + end := strings.IndexByte(content[start:], ']') + if end < 0 { + return nil, fmt.Errorf("list after %q is not closed", marker) + } + matches := quotedValue.FindAllStringSubmatch(content[start:start+end], -1) + values := make([]string, 0, len(matches)) + for _, match := range matches { + values = append(values, match[1]) + } + if len(values) < minimumComparisonVersions { + return nil, fmt.Errorf("list after %q has fewer than two values", marker) + } + return values, nil +} + +func orderedComparisons(versions []string) []comparison { + items := make([]comparison, 0, len(versions)-1) + for index := 1; index < len(versions); index++ { + items = append(items, comparison{left: versions[index-1], right: versions[index], result: -1}) + } + return items +} + +func strictOperatorResult(operator string) (int, bool) { + switch operator { + case "<": + return -1, true + case ">": + return 1, true + case "==", "=": + return 0, true + default: + return 0, false + } +} + +func functionBlock(content, marker string) string { + start := strings.Index(content, marker) + if start < 0 { + return "" + } + rest := content[start+len(marker):] + end := strings.Index(rest, "\n }") + if end < 0 { + end = len(rest) + } + return rest[:end] +} + +func debianVersion(epoch, version, revision string) string { + result := version + if epoch != "0" { + result = epoch + ":" + result + } + if revision != "" { + result += "-" + revision + } + return result +} diff --git a/tools/harvest/extract_test.go b/tools/harvest/extract_test.go new file mode 100644 index 0000000..5650406 --- /dev/null +++ b/tools/harvest/extract_test.go @@ -0,0 +1,102 @@ +package main + +import ( + "reflect" + "testing" +) + +func TestExtractors(t *testing.T) { + tests := []struct { + name string + extract func(map[string]string) ([]comparison, error) + files map[string]string + want []comparison + }{ + { + name: "node-semver", extract: extractNodeSemver, + files: map[string]string{ + "test/fixtures/comparisons.js": "['2.0.0', '1.0.0']\n['v2.0.0', '1.0.0', true]\n", + "test/fixtures/equality.js": "['1.0.0+one', '1.0.0+two']\n", + }, + want: []comparison{{left: "2.0.0", right: "1.0.0", result: 1}, {left: "1.0.0+one", right: "1.0.0+two"}}, + }, + { + name: "pypi", extract: extractPyPI, + files: map[string]string{"tests/test_version.py": "VERSIONS = [\n \"1.0.dev0\",\n \"1.0\",\n]\nassert Version(\"1.0rc1\") == Version(\"1.0c1\")\n"}, + want: []comparison{{left: "1.0.dev0", right: "1.0", result: -1}, {left: "1.0rc1", right: "1.0c1"}}, + }, + { + name: "rubygems", extract: extractRubyGems, + files: map[string]string{"test/rubygems/test_gem_version.rb": "assert_equal(-1, v(\"1.a\") <=> v(\"1\"))\nassert_less_than v(\"2.a\"), v(\"2\")\n"}, + want: []comparison{{left: "1.a", right: "1", result: -1}, {left: "2.a", right: "2", result: -1}}, + }, + { + name: "composer", extract: extractComposer, + files: map[string]string{"tests/ComparatorTest.php": "function compareProvider() { array('2', '>', '1', true); array('1', '>=', '1', true); }\nfunction equalToProvider()\n {\narray('dev-a', '1', false)\n }"}, + want: []comparison{{left: "2", right: "1", result: 1}, {left: "dev-a", right: "1", differentOnly: true}}, + }, + { + name: "pub", extract: extractPub, + files: map[string]string{"pkgs/pub_semver/test/version_test.dart": "group('comparison', () { var versions = ['1.0.0-a', '1.0.0']; test('equality', () { expect(Version.parse('01.0.0'), equals(Version.parse('1.0.0'))); expect(Version.parse('1.0.0-a'), isNot(equals(Version.parse('1.0.0-b')))); }); });"}, + want: []comparison{{left: "1.0.0-a", right: "1.0.0", result: -1}, {left: "01.0.0", right: "1.0.0"}, {left: "1.0.0-a", right: "1.0.0-b", differentOnly: true}}, + }, + { + name: "cargo", extract: extractCargo, + files: map[string]string{"tests/test_version.rs": "fn test_spec_order() { let vs = [\"1.0.0-a\", \"1.0.0\"]; }\nassert!(version(\"1.0.0+1\") < version(\"1.0.0+2\"));\nassert_ne!(version(\"1.0.0+1\"), version(\"1.0.0+2\"));"}, + want: []comparison{{left: "1.0.0-a", right: "1.0.0", result: -1}, {left: "1.0.0+1", right: "1.0.0+2", result: -1}, {left: "1.0.0+1", right: "1.0.0+2", differentOnly: true}}, + }, + { + name: "dpkg", extract: extractDpkg, + files: map[string]string{"lib/dpkg/t/t-version.c": "a = DPKG_VERSION_OBJECT(0, \"1\", \"1\"); b = DPKG_VERSION_OBJECT(1, \"1\", \"1\"); test_pass(dpkg_version_compare(&a, &b) < 0);"}, + want: []comparison{{left: "1-1", right: "1:1-1", result: -1}}, + }, + { + name: "rpm", extract: extractRPM, + files: map[string]string{"tests/rpmvercmp.at": "RPMVERCMP(1.0~rc1, 1.0, -1)\ndnl RPMVERCMP(2, 1, 1)\n"}, + want: []comparison{{left: "1.0~rc1", right: "1.0", result: -1}}, + }, + { + name: "go", extract: extractGo, + files: map[string]string{"semver/semver_test.go": "var tests = []struct { in string; out string }{\n{\"bad\", \"\"},\n{\"also-bad\", \"\"},\n{\"v1\", \"v1.0.0\"},\n}\n"}, + want: []comparison{{left: "bad", right: "also-bad"}, {left: "also-bad", right: "v1", result: -1}}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := test.extract(test.files) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(got, test.want) { + t.Errorf("comparisons = %#v, want %#v", got, test.want) + } + }) + } +} + +func TestBuildTestFileNormalizesResultsAndDeduplicates(t *testing.T) { + source := sourceSpec{name: "reference", scheme: "example"} + file := buildTestFile(source, []comparison{ + {left: "2", right: "1", result: 1}, + {left: "1", right: "2", result: -1}, + {left: "1.0", right: "1", result: 0}, + }) + + if len(file.Tests) != 3 { + t.Fatalf("got %d tests, want 3", len(file.Tests)) + } + if got := file.Tests[0].Input.Versions; !reflect.DeepEqual(got, []string{"2", "1"}) { + t.Errorf("comparison input = %v", got) + } + if got := file.Tests[2].ExpectedOutput; got != true { + t.Errorf("equality output = %v", got) + } +} + +func TestExtractGoReportsMissingTable(t *testing.T) { + _, err := extractGo(map[string]string{"semver/semver_test.go": "package semver\n"}) + if err == nil { + t.Fatal("extractGo succeeded without a tests table") + } +} diff --git a/tools/harvest/main.go b/tools/harvest/main.go new file mode 100644 index 0000000..b5f974a --- /dev/null +++ b/tools/harvest/main.go @@ -0,0 +1,324 @@ +package main + +import ( + "encoding/json" + "errors" + "flag" + "fmt" + "os" + "os/exec" + "path/filepath" +) + +const ( + schemaURL = "https://packageurl.org/schemas/vers-test.schema-0.2.json" + testTypeEquality = "equality" + testGroupRecommended = "recommended" + licenseMIT = "MIT" + testsPerComparison = 2 + directoryMode = 0o755 + fileMode = 0o644 +) + +type sourceSpec struct { + name string + scheme string + repository string + commit string + license string + localPath string + sourceFiles []string + outputFile string + extract func(map[string]string) ([]comparison, error) +} + +type comparison struct { + left string + right string + result int + differentOnly bool +} + +type testFile struct { + Schema string `json:"$schema"` + Tests []testCase `json:"tests"` +} + +type testCase struct { + Description string `json:"description"` + TestGroup string `json:"test_group"` + TestType string `json:"test_type"` + Input comparisonInput `json:"input"` + ExpectedOutput any `json:"expected_output"` +} + +type comparisonInput struct { + InputType string `json:"input_type"` + Versions []string `json:"versions"` +} + +type provenanceFile struct { + Sources []provenanceSource `json:"sources"` +} + +type provenanceSource struct { + Repository string `json:"repository"` + Commit string `json:"commit"` + License string `json:"license"` + SourceFiles []string `json:"source_files"` + GeneratedFiles []string `json:"generated_files"` +} + +var sources = []sourceSpec{ + { + name: "node-semver", scheme: "npm", + repository: "https://github.com/npm/node-semver.git", + commit: "6e05b7637396ac66522cff8731f07cfe0ef49a29", license: "ISC", + localPath: "npm/node-semver", + sourceFiles: []string{"test/fixtures/comparisons.js", "test/fixtures/equality.js"}, + outputFile: "npm_version_cmp_test.json", extract: extractNodeSemver, + }, + { + name: "packaging", scheme: "pypi", + repository: "https://github.com/pypa/packaging.git", + commit: "55cbf1b9426f44455fa1a9e0836f1fc082cc8452", license: "Apache-2.0 OR BSD-2-Clause", + localPath: "pypa/packaging", sourceFiles: []string{"tests/test_version.py"}, + outputFile: "pypi_version_cmp_test.json", extract: extractPyPI, + }, + { + name: "RubyGems", scheme: "gem", + repository: "https://github.com/rubygems/rubygems.git", + commit: "370fe6876eec1714cd0f8824c3f19f4d368dfe7c", license: licenseMIT, + localPath: "rubygems/rubygems", sourceFiles: []string{"test/rubygems/test_gem_version.rb"}, + outputFile: "gem_version_cmp_test.json", extract: extractRubyGems, + }, + { + name: "composer/semver", scheme: "composer", + repository: "https://github.com/composer/semver.git", + commit: "1cbc9b575a27458074d21a3bab95b847c8de387c", license: licenseMIT, + localPath: "composer/semver", sourceFiles: []string{"tests/ComparatorTest.php"}, + outputFile: "composer_version_cmp_test.json", extract: extractComposer, + }, + { + name: "pub_semver", scheme: "pub", + repository: "https://github.com/dart-lang/tools.git", + commit: "a22c3a687dc1b35630fb34c296157d66565429cd", license: "BSD-3-Clause", + localPath: "dart-lang/tools", sourceFiles: []string{"pkgs/pub_semver/test/version_test.dart"}, + outputFile: "pub_version_cmp_test.json", extract: extractPub, + }, + { + name: "semver", scheme: "cargo", + repository: "https://github.com/dtolnay/semver.git", + commit: "280ebcb6edac3aa4cdc545dbff8a26c5ac4861fe", license: "MIT OR Apache-2.0", + localPath: "dtolnay/semver", sourceFiles: []string{"tests/test_version.rs"}, + outputFile: "cargo_version_cmp_test.json", extract: extractCargo, + }, + { + name: "dpkg", scheme: "deb", + repository: "https://salsa.debian.org/dpkg-team/dpkg.git", + commit: "c5efef926d16a72fd9270c8efceeba8872419292", license: "GPL-2.0-or-later", + localPath: "dpkg-team/dpkg", sourceFiles: []string{"lib/dpkg/t/t-version.c"}, + outputFile: "deb_version_cmp_test.json", extract: extractDpkg, + }, + { + name: "RPM", scheme: "rpm", + repository: "https://github.com/rpm-software-management/rpm.git", + commit: "ac5062c43e2337fb43a9179f02c0cc5d7d069802", license: "GPL-2.0-or-later", + localPath: "rpm-software-management/rpm", sourceFiles: []string{"tests/rpmvercmp.at"}, + outputFile: "rpm_version_cmp_test.json", extract: extractRPM, + }, + { + name: "golang.org/x/mod/semver", scheme: "go", + repository: "https://github.com/golang/mod.git", + commit: "d3398d06de5fa5c71083d3d1c26f2cda73508e0f", license: "BSD-3-Clause", + localPath: "golang/mod", sourceFiles: []string{"semver/semver_test.go"}, + outputFile: "go_version_cmp_test.json", extract: extractGo, + }, +} + +func main() { + sourceRoot := flag.String("source-root", "", "read pinned commits from checkouts below this directory") + outputRoot := flag.String("output", filepath.Join("testdata", "local"), "local conformance data directory") + flag.Parse() + + if err := run(*sourceRoot, *outputRoot); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func run(sourceRoot, outputRoot string) error { + testsDir := filepath.Join(outputRoot, "tests") + if err := os.MkdirAll(testsDir, directoryMode); err != nil { + return fmt.Errorf("create tests directory: %w", err) + } + + provenance := provenanceFile{Sources: []provenanceSource{ + { + Repository: "https://github.com/git-pkgs/vers", + Commit: "aca1342a0af1b6308ced629af1913ab42a66dbb5", + License: licenseMIT, + SourceFiles: []string{"composer_pub_test.go"}, + GeneratedFiles: []string{ + "tests/composer_range_containment_test.json", + "tests/composer_range_from_native_test.json", + "tests/pub_range_containment_test.json", + "tests/pub_range_from_native_test.json", + }, + }, + }} + + for _, source := range sources { + files, err := readSource(source, sourceRoot) + if err != nil { + return fmt.Errorf("read %s: %w", source.name, err) + } + comparisons, err := source.extract(files) + if err != nil { + return fmt.Errorf("extract %s: %w", source.name, err) + } + if err := writeJSON(filepath.Join(testsDir, source.outputFile), buildTestFile(source, comparisons)); err != nil { + return err + } + provenance.Sources = append(provenance.Sources, provenanceSource{ + Repository: source.repository, Commit: source.commit, License: source.license, + SourceFiles: source.sourceFiles, GeneratedFiles: []string{filepath.ToSlash(filepath.Join("tests", source.outputFile))}, + }) + } + + return writeJSON(filepath.Join(outputRoot, "provenance.json"), provenance) +} + +func readSource(source sourceSpec, sourceRoot string) (map[string]string, error) { + if sourceRoot != "" { + return readGitFiles(filepath.Join(sourceRoot, filepath.FromSlash(source.localPath)), source.commit, source.sourceFiles) + } + + directory, err := os.MkdirTemp("", "vers-harvest-") + if err != nil { + return nil, err + } + defer func() { + _ = os.RemoveAll(directory) + }() + + if err := runGit(directory, "init", "--quiet"); err != nil { + return nil, err + } + if err := runGit(directory, "remote", "add", "origin", source.repository); err != nil { + return nil, err + } + if err := runGit(directory, "fetch", "--quiet", "--depth=1", "origin", source.commit); err != nil { + return nil, err + } + return readGitFiles(directory, "FETCH_HEAD", source.sourceFiles) +} + +func readGitFiles(repository, revision string, filenames []string) (map[string]string, error) { + if _, err := os.Stat(repository); err != nil { + return nil, fmt.Errorf("open checkout %s: %w", repository, err) + } + + files := make(map[string]string, len(filenames)) + for _, filename := range filenames { + command := exec.Command("git", "-C", repository, "show", revision+":"+filename) + output, err := command.Output() + if err != nil { + return nil, fmt.Errorf("git show %s:%s: %w", revision, filename, err) + } + files[filename] = string(output) + } + return files, nil +} + +func runGit(directory string, arguments ...string) error { + arguments = append([]string{"-C", directory}, arguments...) + command := exec.Command("git", arguments...) + output, err := command.CombinedOutput() + if err != nil { + return fmt.Errorf("%s: %w: %s", command.String(), err, output) + } + return nil +} + +func buildTestFile(source sourceSpec, comparisons []comparison) testFile { + tests := make([]testCase, 0, len(comparisons)*testsPerComparison) + seen := make(map[string]bool, len(comparisons)*testsPerComparison) + appendTest := func(test testCase) { + keyBytes, _ := json.Marshal(test.ExpectedOutput) + left, right := test.Input.Versions[0], test.Input.Versions[1] + if test.TestType == testTypeEquality && right < left { + left, right = right, left + } + key := test.TestType + "\x00" + left + "\x00" + right + "\x00" + string(keyBytes) + if seen[key] { + return + } + seen[key] = true + tests = append(tests, test) + } + for _, item := range comparisons { + left, right, result := item.left, item.right, item.result + if left == right { + continue + } + if item.differentOnly { + appendTest(testCase{ + Description: fmt.Sprintf("%s treats %q and %q as different.", source.name, left, right), + TestGroup: testGroupRecommended, TestType: testTypeEquality, + Input: comparisonInput{InputType: source.scheme, Versions: []string{left, right}}, + ExpectedOutput: false, + }) + continue + } + + testType := "comparison" + expected := any([]string{left, right}) + input := []string{right, left} + description := fmt.Sprintf("%s orders %q before %q.", source.name, left, right) + if result > 0 { + left, right = right, left + expected = []string{left, right} + input = []string{right, left} + description = fmt.Sprintf("%s orders %q before %q.", source.name, left, right) + } else if result == 0 { + testType = testTypeEquality + expected = true + input = []string{left, right} + description = fmt.Sprintf("%s treats %q and %q as equal.", source.name, left, right) + } + + appendTest(testCase{ + Description: description, TestGroup: testGroupRecommended, TestType: testType, + Input: comparisonInput{InputType: source.scheme, Versions: input}, ExpectedOutput: expected, + }) + if result != 0 { + appendTest(testCase{ + Description: fmt.Sprintf("%s treats %q and %q as different.", source.name, item.left, item.right), + TestGroup: testGroupRecommended, TestType: testTypeEquality, + Input: comparisonInput{InputType: source.scheme, Versions: []string{item.left, item.right}}, + ExpectedOutput: false, + }) + } + } + return testFile{Schema: schemaURL, Tests: tests} +} + +func writeJSON(filename string, value any) error { + data, err := json.MarshalIndent(value, "", " ") + if err != nil { + return fmt.Errorf("encode %s: %w", filename, err) + } + data = append(data, '\n') + if err := os.WriteFile(filename, data, fileMode); err != nil { + return fmt.Errorf("write %s: %w", filename, err) + } + return nil +} + +func requireComparisons(items []comparison) ([]comparison, error) { + if len(items) == 0 { + return nil, errors.New("no comparisons found") + } + return items, nil +} diff --git a/version.go b/version.go index f6c15e2..4528eb3 100644 --- a/version.go +++ b/version.go @@ -330,6 +330,9 @@ func CompareWithScheme(a, b, scheme string) int { if a == b { return 0 } + if scheme == schemeGem || scheme == schemeRubyGems || scheme == schemeGo || scheme == schemeGolang { + return compareFuncFor(scheme)(a, b) + } if a == "" { return -1 } @@ -343,8 +346,14 @@ func CompareWithScheme(a, b, scheme string) int { // compareFuncFor returns the version comparison function for a scheme. func compareFuncFor(scheme string) func(a, b string) int { switch scheme { - case schemeSemVer, schemeNPM, schemeCargo, schemeGo, schemeGolang, schemeHex, schemeElixir, schemeNginx: + case schemeSemVer, schemeHex, schemeElixir, schemeNginx: return compareSemver + case schemeNPM: + return compareNPM + case schemeCargo: + return compareCargo + case schemeGo, schemeGolang: + return compareGo case schemeComposer: return compareComposer case schemePub: