extern crate toml;
use chrono::NaiveDate;
use std::fmt::Debug;
use super::*;
static TEST_FILE: &'static str =
include_str!("../examples/channel-rust-1.24.toml");
static ARM64_TRIPLE: &'static str = "aarch64-unknown-linux-gnu";
#[test]
fn it_works() {
let ch: Channel = toml::from_str(TEST_FILE).unwrap();
assert_eq!(ch.date, NaiveDate::from_ymd(2018, 2, 15));
let pkgs: Vec<_> = ch.pkg.keys().cloned().collect();
assert_eq!(
pkgs,
vec![
"cargo",
"rls-preview",
"rust",
"rust-analysis",
"rust-docs",
"rust-mingw",
"rust-src",
"rust-std",
"rustc",
"rustfmt-preview",
]
);
let cargo = ch.pkg.get("cargo").unwrap();
assert_eq!(cargo.version, "0.25.0 (8c93e0895 2018-02-01)");
assert_eq!(cargo.git_commit_hash, None);
let cargo_for_aarch64 = cargo.target.get(ARM64_TRIPLE).unwrap();
let cargo_for_aarch64_gz = cargo_for_aarch64
.standalone
.get(&ArchiveFormat::TarGzip)
.unwrap();
assert_eq!(
cargo_for_aarch64_gz.url,
"https://static.rust-lang.org/dist/2018-02-15/\
cargo-0.25.0-aarch64-unknown-linux-gnu.tar.gz"
.parse()
.unwrap(),
);
assert_eq!(
cargo_for_aarch64_gz.hash,
"085fee1d520ca851dc14d8750ee843ebea81eec75c58a789396884171975e599"
);
assert_eq!(cargo_for_aarch64.components, Vec::<ArtefactToken>::new());
assert_eq!(cargo_for_aarch64.extensions, Vec::<ArtefactToken>::new());
let rust = ch.pkg.get("rust").unwrap();
assert_eq!(rust.version, "1.24.0 (4d90ac38c 2018-02-12)");
assert_eq!(
rust.git_commit_hash,
Some("4d90ac38c0b61bb69470b61ea2cccea0df48d9e5".into())
);
let rust_for_aarch64 = rust.target.get(ARM64_TRIPLE).unwrap();
let rust_for_aarch64_xz = rust_for_aarch64
.standalone
.get(&ArchiveFormat::TarXz)
.unwrap();
assert_eq!(
rust_for_aarch64_xz.url,
"https://static.rust-lang.org/dist/2018-02-15/\
rust-1.24.0-aarch64-unknown-linux-gnu.tar.xz"
.parse()
.unwrap(),
);
assert_eq!(
rust_for_aarch64_xz.hash,
"dd09d93396825f0a9f7806e677a87eb77f7ce76836568004264631027eaccc50"
);
fn mktoken(pkg: &str) -> ArtefactToken {
ArtefactToken {
pkg: pkg.into(),
target: ARM64_TRIPLE.into(),
}
};
assert_eq!(
rust_for_aarch64.components,
[
mktoken("rustc"),
mktoken("rust-std"),
mktoken("cargo"),
mktoken("rust-docs"),
]
);
assert_eq!(rust_for_aarch64.extensions.len(), 62);
assert_eq!(ch.renames.get("rls").unwrap(), "rls-preview");
assert_eq!(
format!("{}", ch),
"Rust release channel for version 1.24.0 (4d90ac38c 2018-02-12), \
dated 2018-02-15",
);
}
#[test]
fn new_channel() {
let ch = Channel::with_date(NaiveDate::from_ymd(1970, 1, 1));
assert_eq!(ch.date, NaiveDate::from_ymd(1970, 01, 01));
assert_eq!(ch.pkg.len(), 0);
assert_eq!(ch.renames.len(), 0);
assert_eq!(
format!("{}", ch),
"Rust release channel for version <unknown>, dated 1970-01-01",
);
}
#[test]
fn deserialize_channel() {
let channel_toml = "\
manifest-version = \"2\"
date = \"1970-01-02\"
";
let ch: Channel = channel_toml.parse().expect("Could not parse TOML");
assert_eq!(ch.date, NaiveDate::from_ymd(1970, 01, 02));
assert_eq!(ch.pkg.len(), 0);
assert_eq!(ch.renames.len(), 0);
}
#[test]
fn deserialize_rejects_v1() {
let channel_toml = "\
manifest-version = \"1\"
date = \"1970-01-02\"
";
let err = channel_toml
.parse::<Channel>()
.expect_err("Allowed manifest v1!");
assert_eq!(
format!("{}", err),
"unknown variant `1`, expected `2` for key `manifest-version`"
);
}
#[test]
fn deserialize_rejects_v3() {
let channel_toml = "\
manifest-version = \"3\"
date = \"1970-01-02\"
";
let err = channel_toml
.parse::<Channel>()
.expect_err("Allowed manifest v3!");
assert_eq!(
format!("{}", err),
"unknown variant `3`, expected `2` for key `manifest-version`"
);
}
#[test]
fn deserialize_rejects_unknown_version() {
let channel_toml = "\
manifest-version = \"freddled gruntbuggly\"
date = \"1970-01-02\"
";
let err = channel_toml
.parse::<Channel>()
.expect_err("Allowed manifest weird version!");
assert_eq!(
format!("{}", err),
"unknown variant `freddled gruntbuggly`, \
expected `2` for key `manifest-version`"
);
}
#[test]
fn deserialize_rejects_invalid_date() {
let channel_toml = "\
manifest-version = \"2\"
date = \"invalid date\"
";
let err = channel_toml
.parse::<Channel>()
.expect_err("Allowed manifest weird date!");
assert_eq!(format!("{}", err), "input contains invalid characters");
}
#[test]
fn deserialize_rejects_invalid_url() {
let channel_toml = "\
manifest-version = \"2\"
date = \"1970-01-01\"
[pkg.mypackage]
version = \"1.2.3\"
[pkg.mypackage.target.aarch64-unknown-linux-gnu]
available = true
url = \"some invalid url\"
hash = \"aa0a89d80329fec6f9e84b79c1674c5427034408630c35da1be442c7da6d2364\"
";
let err = channel_toml
.parse::<Channel>()
.expect_err("Allowed manifest weird date!");
assert_eq!(format!("{}", err), "relative URL without a base");
}
#[test]
fn serialize_channel() {
let mut ch = Channel::with_date(NaiveDate::from_ymd(1970, 1, 1));
ch.pkg.insert(
"mytool".into(),
Package {
version: "0.1.0".into(),
git_commit_hash: None,
target: Default::default(),
},
);
ch.renames.insert("myoldtool".into(), "mytool".into());
assert_eq!(
ch.to_string().expect("could not serialize"),
"manifest-version = \"2\"\n\
date = \"1970-01-01\"\n\
[pkg.mytool]\n\
version = \"0.1.0\"\n\
[renames.myoldtool]\n\
to = \"mytool\"\n\
"
);
}
#[test]
fn lookup_unknown_token() {
let ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
assert_eq!(
ch.lookup_artefact(ArtefactQuery::new(
"mystery-package",
"mystery-unknown-linux-gnu"
)),
None
);
}
#[test]
fn lookup_known_token() {
let ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
let art =
ch.lookup_artefact(ArtefactQuery::new("rls-preview", ARM64_TRIPLE))
.expect("Could not find rls-preview");
let archive = art.standalone
.get(&ArchiveFormat::TarXz)
.expect("no .tar.xz?");
assert_eq!(
archive.url,
"https://static.rust-lang.org/dist/2018-02-15/\
rls-0.124.0-aarch64-unknown-linux-gnu.tar.xz"
.parse()
.unwrap(),
);
assert_eq!(
archive.hash,
"0970bd12581e5389b3c0af393d4ad58f2710ef62c68ff0eaf7523e5362db6c16"
);
}
#[test]
fn lookup_known_token_with_rename() {
let ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
let art = ch.lookup_artefact(ArtefactQuery::new("rls", ARM64_TRIPLE))
.expect("Could not find rls");
let archive = art.standalone
.get(&ArchiveFormat::TarXz)
.expect("no .tar.xz?");
assert_eq!(
archive.url,
"https://static.rust-lang.org/dist/2018-02-15/\
rls-0.124.0-aarch64-unknown-linux-gnu.tar.xz"
.parse()
.unwrap(),
);
assert_eq!(
archive.hash,
"0970bd12581e5389b3c0af393d4ad58f2710ef62c68ff0eaf7523e5362db6c16"
);
}
fn test_sort_cycle<T>(input: &[T], output: Vec<T>)
where
T: Ord + Clone + Debug,
{
assert_eq!(output, sort_cycle(input));
}
#[test]
fn sort_cycle_acccepts_empty_cyle() {
test_sort_cycle::<u32>(&[], vec![]);
}
#[test]
fn sort_cycle_puts_smallest_item_first() {
test_sort_cycle(&[2, 1], vec![1, 2]);
}
#[test]
fn sort_cycle_preserves_cycle_order() {
test_sort_cycle(&[2, 1, 3], vec![1, 3, 2]);
}
#[test]
fn sort_cycle_leaves_sorted_cycle_alone() {
test_sort_cycle(&[1, 4, 3, 2], vec![1, 4, 3, 2]);
}
#[test]
fn validate_accepts_valid_manifest() {
let ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
assert_eq!(ch.validate(), vec![]);
}
#[test]
fn validate_rejects_bogus_rename_destination() {
let mut ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
ch.renames.insert("foo".into(), "bar".into());
assert_eq!(
ch.validate(),
vec![ValidationError::RenameToUnknownPackage {
old: "foo",
new: "bar",
}],
)
}
#[test]
fn validate_rejects_package_component_with_bogus_package() {
let mut ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
{
let cargo_pkg = ch.pkg.get_mut("cargo").expect("no cargo?");
let cargo_for_aarch64 =
cargo_pkg.target.get_mut(ARM64_TRIPLE).expect("no aarch64?");
cargo_for_aarch64.components.push(ArtefactToken {
pkg: "foo".into(),
target: "bar".into(),
});
}
assert_eq!(
ch.validate(),
vec![ValidationError::ArtefactHasUnknownComponent {
artefact: ArtefactQuery::new("cargo", ARM64_TRIPLE),
component_pkg: "foo",
}],
)
}
#[test]
fn validate_rejects_package_component_with_bogus_target() {
let mut ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
{
let cargo_pkg = ch.pkg.get_mut("cargo").expect("no cargo?");
let cargo_for_aarch64 =
cargo_pkg.target.get_mut(ARM64_TRIPLE).expect("no aarch64?");
cargo_for_aarch64.components.push(ArtefactToken {
pkg: "rustc".into(),
target: "bar".into(),
});
}
assert_eq!(
ch.validate(),
vec![ValidationError::ArtefactComponentHasUnknownTarget {
artefact: ArtefactQuery::new("cargo", ARM64_TRIPLE),
component: ArtefactQuery::new("rustc", "bar"),
}],
)
}
#[test]
fn validate_rejects_package_extension_with_bogus_package() {
let mut ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
{
let cargo_pkg = ch.pkg.get_mut("cargo").expect("no cargo?");
let cargo_for_aarch64 =
cargo_pkg.target.get_mut(ARM64_TRIPLE).expect("no aarch64?");
cargo_for_aarch64.extensions.push(ArtefactToken {
pkg: "foo".into(),
target: "bar".into(),
});
}
assert_eq!(
ch.validate(),
vec![ValidationError::ArtefactHasUnknownExtension {
artefact: ArtefactQuery::new("cargo", ARM64_TRIPLE),
extension_pkg: "foo",
}],
)
}
#[test]
fn validate_rejects_package_extension_with_bogus_target() {
let mut ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
{
let cargo_pkg = ch.pkg.get_mut("cargo").expect("no cargo?");
let cargo_for_aarch64 =
cargo_pkg.target.get_mut(ARM64_TRIPLE).expect("no aarch64?");
cargo_for_aarch64.extensions.push(ArtefactToken {
pkg: "rustc".into(),
target: "bar".into(),
});
}
assert_eq!(
ch.validate(),
vec![ValidationError::ArtefactExtensionHasUnknownTarget {
artefact: ArtefactQuery::new("cargo", ARM64_TRIPLE),
extension: ArtefactQuery::new("rustc", "bar"),
}],
)
}
#[test]
fn validate_rejects_renaming_a_package_to_itself() {
let mut ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
ch.renames.insert("rustc".into(), "rustc".into());
assert_eq!(
ch.validate(),
vec![ValidationError::RenameToItself("rustc")],
)
}
#[test]
fn validate_rejects_a_package_that_exists() {
let mut ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
ch.renames.insert("rustc".into(), "cargo".into());
assert_eq!(
ch.validate(),
vec![ValidationError::RenameExistingPackage("rustc")],
)
}
#[test]
fn validate_rejects_component_direct_dependency_loop() {
let mut ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
ch.pkg
.get_mut("cargo")
.and_then(|pkg| pkg.target.get_mut(ARM64_TRIPLE))
.expect("No cargo for Linux ARM64?")
.components
.push(ArtefactToken::new("cargo".into(), ARM64_TRIPLE.into()));
let dependencies = vec![ArtefactQuery::new("cargo", ARM64_TRIPLE)]
.into_iter()
.collect();
assert_eq!(
ch.validate(),
vec![ValidationError::DependencyLoop(dependencies)],
)
}
#[test]
fn validate_rejects_component_arbitrary_dependency_loops() {
let mut ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
ch.pkg
.get_mut("cargo")
.and_then(|pkg| pkg.target.get_mut(ARM64_TRIPLE))
.expect("No cargo for Linux ARM64?")
.components
.push(ArtefactToken::new("rustc".into(), ARM64_TRIPLE.into()));
ch.pkg
.get_mut("rustc")
.and_then(|pkg| pkg.target.get_mut(ARM64_TRIPLE))
.expect("No rustc for Linux ARM64?")
.components
.push(ArtefactToken::new("cargo".into(), ARM64_TRIPLE.into()));
let dependencies = vec![
ArtefactQuery::new("cargo", ARM64_TRIPLE),
ArtefactQuery::new("rustc", ARM64_TRIPLE),
].into_iter()
.collect();
assert_eq!(
ch.validate(),
vec![ValidationError::DependencyLoop(dependencies)],
)
}
#[test]
fn validate_accepts_dependency_loop_via_extension() {
let mut ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
ch.pkg
.get_mut("cargo")
.and_then(|pkg| pkg.target.get_mut(ARM64_TRIPLE))
.expect("No cargo for Linux ARM64?")
.components
.push(ArtefactToken::new("rustc".into(), ARM64_TRIPLE.into()));
ch.pkg
.get_mut("rustc")
.and_then(|pkg| pkg.target.get_mut(ARM64_TRIPLE))
.expect("No rustc for Linux ARM64?")
.extensions
.push(ArtefactToken::new("cargo".into(), ARM64_TRIPLE.into()));
assert_eq!(ch.validate(), vec![])
}
#[test]
fn validate_detects_multiple_problems() {
let mut ch: Channel = TEST_FILE.parse().expect("Could not parse TOML");
ch.renames.insert("foo".into(), "bar".into());
{
let cargo_pkg = ch.pkg.get_mut("cargo").expect("no cargo?");
let cargo_for_aarch64 =
cargo_pkg.target.get_mut(ARM64_TRIPLE).expect("no aarch64?");
cargo_for_aarch64.components.push(ArtefactToken {
pkg: "rustc".into(),
target: "bar".into(),
});
cargo_for_aarch64.extensions.push(ArtefactToken {
pkg: "foo".into(),
target: "bar".into(),
});
}
let mut errors = ch.validate();
errors.sort();;
assert_eq!(
errors,
vec![
ValidationError::RenameToUnknownPackage {
old: "foo",
new: "bar",
},
ValidationError::ArtefactComponentHasUnknownTarget {
artefact: ArtefactQuery::new("cargo", ARM64_TRIPLE),
component: ArtefactQuery::new("rustc", "bar"),
},
ValidationError::ArtefactHasUnknownExtension {
artefact: ArtefactQuery::new("cargo", ARM64_TRIPLE),
extension_pkg: "foo",
},
],
)
}
#[test]
fn test_errors_are_send_and_sync() {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
assert_send::<ValidationError>();
assert_sync::<ValidationError>();
}
#[test]
fn test_display_package() {
let mut pkg = Package::new("1.2.3".into());
assert_eq!(format!("{}", pkg), "Package version 1.2.3 for 0 target(s)",);
pkg.target.insert(ARM64_TRIPLE.into(), Default::default());
assert_eq!(format!("{}", pkg), "Package version 1.2.3 for 1 target(s)",)
}
#[test]
fn test_display_artefact() {
let mut artefact = Artefact::new();
assert_eq!(
format!("{}", artefact),
"Artefact in 0 format(s), with 0 component(s) and 0 extension(s)",
);
artefact.components.push(ArtefactToken {
pkg: "foo".into(),
target: "bar".into(),
});
assert_eq!(
format!("{}", artefact),
"Artefact in 0 format(s), with 1 component(s) and 0 extension(s)",
);
artefact.extensions.push(ArtefactToken {
pkg: "foo".into(),
target: "bar".into(),
});
assert_eq!(
format!("{}", artefact),
"Artefact in 0 format(s), with 1 component(s) and 1 extension(s)",
);
artefact.standalone.insert(
ArchiveFormat::TarGzip,
ArchiveSource {
url: "https://example.com/rust/archive.tar.gz".parse().unwrap(),
hash: "abcd1234".into(),
},
);
assert_eq!(
format!("{}", artefact),
"Artefact in 1 format(s), with 1 component(s) and 1 extension(s)",
);
}
#[test]
fn test_display_artefactsource() {
let source = ArchiveSource::new(
"https://example.com/rust/archive.tar.gz".parse().unwrap(),
"abcd1234".into(),
);
assert_eq!(
format!("{}", source),
"<https://example.com/rust/archive.tar.gz>",
);
}
#[test]
fn test_display_archiveformat() {
assert_eq!(format!("{}", ArchiveFormat::TarGzip), ".tar.gz",);
assert_eq!(format!("{}", ArchiveFormat::TarXz), ".tar.xz",);
assert_eq!(
format!("{}", ArchiveFormat::ReservedForFutureExpansion),
"<unknown>",
);
}
#[test]
fn test_display_artefacttoken() {
let token = ArtefactToken::new("somepackage".into(), ARM64_TRIPLE.into());
assert_eq!(
format!("{}", token),
"Package somepackage built for aarch64-unknown-linux-gnu",
)
}