use crate::specifier::Specifier;
#[test]
fn same_version_different_ranges() {
let cases: Vec<(&str, &str)> = vec![
("1.4.1", "^1.4.1"),
("1.4.1", "~1.4.1"),
("1.4.1", ">=1.4.1"),
("1.4.1", ">1.4.1"),
("1.4.1", "<=1.4.1"),
("1.4.1", "<1.4.1"),
("^1.4.1", "~1.4.1"),
("^1.4.1", ">=1.4.1"),
("~1.4.1", ">=1.4.1"),
(">1.4.1", "<=1.4.1"),
("1.4.1-alpha.1", "^1.4.1-alpha.1"),
("1.4.1-beta.2", "~1.4.1-beta.2"),
("^1.4.1-rc.3", ">=1.4.1-rc.3"),
];
for (a, b) in cases {
assert!(
Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have same version number"
);
assert!(
Specifier::new(b).has_same_version_number_as(&Specifier::new(a)),
"Expected {b} and {a} to have same version number (symmetry check)"
);
}
}
#[test]
fn different_versions() {
let cases: Vec<(&str, &str)> = vec![
("1.4.1", "1.4.2"),
("^1.4.1", "^1.4.2"),
("~1.4.1", "~1.4.2"),
("1.4.1", "1.5.1"),
("^1.4.1", "^1.5.1"),
("1.4.1", "2.4.1"),
("^1.4.1", "^2.4.1"),
("1.4.1-alpha.1", "1.4.1-alpha.2"),
("1.4.1-alpha.1", "1.4.1-beta.1"),
("^1.4.1-alpha.1", "^1.4.1-alpha.2"),
("1.4.1-alpha.1", "1.4.2-alpha.1"),
("1.4.1", "1.4.1-alpha.1"),
("1.0.0", "2.0.0"),
("^1.2.3", "~4.5.6"),
];
for (a, b) in cases {
assert!(
!Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have different version numbers"
);
assert!(
!Specifier::new(b).has_same_version_number_as(&Specifier::new(a)),
"Expected {b} and {a} to have different version numbers (symmetry check)"
);
}
}
#[test]
fn with_workspace_protocol() {
let cases_same: Vec<(&str, &str)> = vec![
("workspace:1.4.1", "workspace:1.4.1"),
("workspace:^1.4.1", "workspace:~1.4.1"),
("workspace:1.4.1", "workspace:^1.4.1"),
("workspace:1.4.1", "1.4.1"),
("workspace:^1.4.1", "^1.4.1"),
("workspace:~1.4.1", "~1.4.1"),
];
for (a, b) in cases_same {
assert!(
Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have same version number"
);
}
let cases_identical_unresolved: Vec<(&str, &str)> = vec![
("workspace:*", "workspace:*"),
("workspace:^", "workspace:^"),
("workspace:~", "workspace:~"),
];
for (a, b) in cases_identical_unresolved {
assert!(
Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have same version number (identical unresolved workspace protocols)"
);
}
let cases_false: Vec<(&str, &str)> = vec![
("workspace:*", "workspace:^"),
("workspace:*", "workspace:~"),
("workspace:^", "workspace:~"),
("workspace:*", "1.4.1"),
("workspace:^", "^1.4.1"),
("workspace:~", "~1.4.1"),
];
for (a, b) in cases_false {
assert!(
!Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to return false (different or incomparable)"
);
}
}
#[test]
fn with_npm_alias() {
let cases_same: Vec<(&str, &str)> = vec![
("npm:foo@1.4.1", "npm:bar@1.4.1"),
("npm:foo@^1.4.1", "npm:bar@~1.4.1"),
("npm:@scope/pkg@1.4.1", "npm:@other/pkg@1.4.1"),
("npm:foo@1.4.1", "1.4.1"),
("npm:foo@^1.4.1", "^1.4.1"),
("npm:@scope/pkg@~1.4.1", "~1.4.1"),
("npm:foo@1.4.1-alpha.1", "npm:bar@1.4.1-alpha.1"),
("npm:foo@^1.4.1-beta", "^1.4.1-beta"),
];
for (a, b) in cases_same {
assert!(
Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have same version number"
);
}
let cases_different: Vec<(&str, &str)> = vec![
("npm:foo@1.4.1", "npm:foo@1.4.2"),
("npm:foo@^1.4.1", "npm:foo@^1.5.1"),
("npm:@scope/pkg@1.4.1", "npm:@scope/pkg@2.4.1"),
("npm:foo", "npm:bar"),
("npm:foo", "1.4.1"),
("npm:foo@1.4.1", "npm:bar"),
];
for (a, b) in cases_different {
assert!(
!Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have different version numbers or no node_version"
);
}
}
#[test]
fn with_git_urls() {
let cases_same: Vec<(&str, &str)> = vec![
("git@github.com:npm/cli.git#1.4.1", "git@github.com:npm/cli.git#1.4.1"),
("git@github.com:npm/cli.git#^1.4.1", "git@github.com:npm/cli.git#~1.4.1"),
("git@github.com:npm/cli.git#1.4.1", "git@github.com:other/pkg.git#1.4.1"),
(
"git+ssh://git@github.com/npm/cli#^1.4.1",
"git+ssh://git@github.com/npm/cli#>=1.4.1",
),
("github:user/repo#1.4.1", "github:other/repo#1.4.1"),
("git@github.com:npm/cli.git#1.4.1", "1.4.1"),
("git@github.com:npm/cli.git#^1.4.1", "^1.4.1"),
("github:user/repo#~1.4.1", "~1.4.1"),
(
"git@github.com:npm/cli.git#1.4.1-alpha.1",
"git@github.com:npm/cli.git#1.4.1-alpha.1",
),
("git@github.com:npm/cli.git#^1.4.1-beta", "^1.4.1-beta"),
];
for (a, b) in cases_same {
assert!(
Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have same version number"
);
}
let cases_different: Vec<(&str, &str)> = vec![
("git@github.com:npm/cli.git#1.4.1", "git@github.com:npm/cli.git#1.4.2"),
("git@github.com:npm/cli.git#^1.4.1", "git@github.com:npm/cli.git#^1.5.1"),
("github:user/repo#1.4.1", "github:user/repo#2.4.1"),
("git@github.com:npm/cli.git", "git@github.com:npm/cli.git#main"),
("git@github.com:npm/cli.git#main", "git@github.com:npm/cli.git#develop"),
("git@github.com:npm/cli.git", "1.4.1"),
("git@github.com:npm/cli.git#main", "^1.4.1"),
];
for (a, b) in cases_different {
assert!(
!Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have different version numbers or no node_version"
);
}
}
#[test]
fn major_and_minor_variants() {
let cases_different: Vec<(&str, &str)> = vec![
("1", "1.0.0"),
("1", "1.4.1"),
("1", "^1.0.0"),
("^1", "^1.0.0"),
("1.4", "1.4.0"),
("1.4", "1.4.1"),
("1.4", "^1.4.0"),
("^1.4", "^1.4.0"),
("1", "1.4"),
("^1", "^1.4"),
];
for (a, b) in cases_different {
assert!(
!Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have different version numbers (padded variants)"
);
}
let cases_same: Vec<(&str, &str)> = vec![
("1", "^1"),
("1", "~1"),
("^1", "~1"),
("1.4", "^1.4"),
("1.4", "~1.4"),
("^1.4", "~1.4"),
("1", "1.999999.999999"),
("^1", "^1.999999.999999"),
("1.4", "1.4.999999"),
("^1.4", "^1.4.999999"),
];
for (a, b) in cases_same {
assert!(
Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have same version number (same padded values)"
);
}
}
#[test]
fn specifiers_without_node_version() {
let cases: Vec<(&str, &str)> = vec![
("latest", "next"),
("latest", "canary"),
("next", "beta"),
("latest", "1.4.1"),
("https://example.com/package.tgz", "https://other.com/pkg.tgz"),
("http://example.com/package.tgz", "1.4.1"),
("file:../foo", "file:../bar"),
("file:./local", "1.4.1"),
(">=1.2.3 <2.0.0", ">=2.0.0 <3.0.0"),
("^1.2.3 || ^2.0.0", "^3.0.0 || ^4.0.0"),
(">=1.2.3 <2.0.0", "1.4.1"),
("workspace:*", "workspace:^"),
("workspace:~", "workspace:*"),
("npm:foo", "npm:bar"),
("git@github.com:npm/cli.git", "git@github.com:npm/cli.git#main"),
(
"git+ssh://git@github.com/npm/cli#feature",
"git+ssh://git@github.com/npm/cli#develop",
),
("1.4.1", "latest"),
("^1.4.1", "https://example.com/package.tgz"),
("~1.4.1", "file:../foo"),
("npm:foo@1.4.1", "npm:bar"),
("git@github.com:npm/cli.git#1.4.1", "git@github.com:npm/cli.git"),
];
for (a, b) in cases {
assert!(
!Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to return false (at least one has no node_version)"
);
}
}
#[test]
fn self_comparison() {
let cases: Vec<&str> = vec![
"1.4.1",
"^1.4.1",
"~1.4.1",
">=1.4.1",
"1.4.1-alpha.1",
"^1.4.1-beta.2",
"1",
"1.4",
"^1",
"~1.4",
"npm:foo@1.4.1",
"npm:@scope/pkg@^1.4.1",
"git@github.com:npm/cli.git#1.4.1",
"github:user/repo#^1.4.1",
];
for value in cases {
let spec = Specifier::new(value);
assert!(
spec.has_same_version_number_as(&spec),
"Expected {value} to have same version number as itself"
);
}
}
#[test]
fn comprehensive_exact_version_matches() {
let version = "1.4.1";
let variants: Vec<&str> = vec![
"1.4.1",
"^1.4.1",
"~1.4.1",
">=1.4.1",
">1.4.1",
"<=1.4.1",
"<1.4.1",
"npm:foo@1.4.1",
"npm:@scope/pkg@1.4.1",
"npm:foo@^1.4.1",
"npm:foo@~1.4.1",
"git@github.com:npm/cli.git#1.4.1",
"git@github.com:npm/cli.git#^1.4.1",
"git+ssh://git@github.com/npm/cli#~1.4.1",
"github:user/repo#1.4.1",
];
for i in 0..variants.len() {
for j in 0..variants.len() {
let a = variants[i];
let b = variants[j];
assert!(
Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have same version number ({version})"
);
}
}
}
#[test]
fn comprehensive_prerelease_version_matches() {
let version = "1.4.1-alpha.1";
let variants: Vec<&str> = vec![
"1.4.1-alpha.1",
"^1.4.1-alpha.1",
"~1.4.1-alpha.1",
">=1.4.1-alpha.1",
"npm:foo@1.4.1-alpha.1",
"npm:foo@^1.4.1-alpha.1",
"git@github.com:npm/cli.git#1.4.1-alpha.1",
"github:user/repo#~1.4.1-alpha.1",
];
for i in 0..variants.len() {
for j in 0..variants.len() {
let a = variants[i];
let b = variants[j];
assert!(
Specifier::new(a).has_same_version_number_as(&Specifier::new(b)),
"Expected {a} and {b} to have same version number ({version})"
);
}
}
}
#[test]
fn edge_cases() {
assert!(Specifier::new("0.0.0").has_same_version_number_as(&Specifier::new("^0.0.0")));
assert!(Specifier::new("0.0.0").has_same_version_number_as(&Specifier::new("~0.0.0")));
assert!(!Specifier::new("0.0.0").has_same_version_number_as(&Specifier::new("0.0.1")));
assert!(!Specifier::new("0.0.0").has_same_version_number_as(&Specifier::new("0.1.0")));
assert!(!Specifier::new("0.0.0").has_same_version_number_as(&Specifier::new("1.0.0")));
assert!(Specifier::new("999.999.999").has_same_version_number_as(&Specifier::new("^999.999.999")));
assert!(Specifier::new("1.0.0-alpha.1.2.3").has_same_version_number_as(&Specifier::new("^1.0.0-alpha.1.2.3")));
assert!(!Specifier::new("1.0.0-alpha.1.2.3").has_same_version_number_as(&Specifier::new("1.0.0-alpha.1.2.4")));
}
#[test]
fn none_variant() {
let cases: Vec<&str> = vec!["*", "latest", "1.4.1", "^1.4.1"];
let none_spec = Specifier::new("*");
for value in cases {
assert!(
!none_spec.has_same_version_number_as(&Specifier::new(value)),
"Expected None variant (*) and {value} to return false"
);
}
}