diff --git a/src/web/mod.rs b/src/web/mod.rs index 3fe82f2e6..2a14c2556 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -186,6 +186,7 @@ impl Handler for CratesfyiHandler { } /// Represents the possible results of attempting to load a version requirement. +#[derive(Debug, Clone, PartialEq, Eq)] enum MatchVersion { /// `match_version` was given an exact version, which matched a saved crate version. Exact(String), @@ -226,19 +227,15 @@ fn match_version(conn: &Connection, name: &str, version: Option<&str>) -> MatchV .map(|v| if v == "newest" || v == "latest" { "*".to_owned() } else { v }) .unwrap_or("*".to_string()); - let versions = { - let mut versions = Vec::new(); - let rows = conn.query("SELECT versions FROM crates WHERE name = $1", &[&name]).unwrap(); + let versions: Vec = { + let query = "SELECT version + FROM releases INNER JOIN crates ON releases.crate_id = crates.id + WHERE name = $1 AND yanked = false"; + let rows = conn.query(query, &[&name]).unwrap(); if rows.len() == 0 { return MatchVersion::None; } - let versions_json: Json = rows.get(0).get(0); - for version in versions_json.as_array().unwrap() { - let version: String = version.as_string().unwrap().to_owned(); - versions.push(version); - } - - versions + rows.iter().map(|row| row.get(0)).collect() }; // first check for exact match @@ -274,18 +271,18 @@ fn match_version(conn: &Connection, name: &str, version: Option<&str>) -> MatchV versions_sem }; - // semver is acting weird for '*' (any) range if a crate only have pre-release versions - // return first version if requested version is '*' - if req_version == "*" && !versions_sem.is_empty() { - return MatchVersion::Semver(format!("{}", versions_sem[0])); - } - for version in &versions_sem { if req_sem_ver.matches(&version) { return MatchVersion::Semver(format!("{}", version)); } } + // semver is acting weird for '*' (any) range if a crate only have pre-release versions + // return first version if requested version is '*' + if req_version == "*" && !versions_sem.is_empty() { + return MatchVersion::Semver(format!("{}", versions_sem[0])); + } + MatchVersion::None } @@ -503,14 +500,87 @@ impl ToJson for MetaData { #[cfg(test)] mod test { - extern crate env_logger; + use crate::test::*; + use web::{match_version, MatchVersion}; + + fn release(version: &str, db: &TestDatabase) -> i32 { + db.fake_release().name("foo").version(version).create().unwrap() + } + fn version(v: Option<&str>, db: &TestDatabase) -> MatchVersion { + match_version(&db.conn(), "foo", v) + } #[test] fn test_index_returns_success() { - crate::test::wrapper(|env| { + wrapper(|env| { let web = env.frontend(); assert!(web.get("/").send()?.status().is_success()); Ok(()) }); } + + #[test] + // https://github.com/rust-lang/docs.rs/issues/223 + fn prereleases_are_not_considered_for_semver() { + wrapper(|env| { + let db = env.db(); + let version = |v| version(v, db); + let release = |v| release(v, db); + + release("0.3.1-pre"); + assert_eq!(version(Some("*")), MatchVersion::Semver("0.3.1-pre".into())); + + release("0.3.1-alpha"); + assert_eq!(version(Some("0.3.1-alpha")), MatchVersion::Exact("0.3.1-alpha".into())); + + release("0.3.0"); + let three = MatchVersion::Semver("0.3.0".into()); + assert_eq!(version(None), three); + // same thing but with "*" + assert_eq!(version(Some("*")), three); + // make sure exact matches still work + assert_eq!(version(Some("0.3.0")), MatchVersion::Exact("0.3.0".into())); + + Ok(()) + }); + } + + #[test] + // https://github.com/rust-lang/docs.rs/issues/221 + fn yanked_crates_are_not_considered() { + wrapper(|env| { + let db = env.db(); + + let release_id = release("0.3.0", db); + let query = "UPDATE releases SET yanked = true WHERE id = $1 AND version = '0.3.0'"; + db.conn().query(query, &[&release_id]).unwrap(); + assert_eq!(version(None, db), MatchVersion::None); + assert_eq!(version(Some("0.3"), db), MatchVersion::None); + + release("0.1.0+4.1", db); + assert_eq!(version(Some("0.1.0+4.1"), db), MatchVersion::Exact("0.1.0+4.1".into())); + assert_eq!(version(None, db), MatchVersion::Semver("0.1.0+4.1".into())); + + Ok(()) + }); + } + + #[test] + // vaguely related to https://github.com/rust-lang/docs.rs/issues/395 + fn metadata_has_no_effect() { + wrapper(|env| { + let db = env.db(); + + release("0.1.0+4.1", db); + release("0.1.1", db); + assert_eq!(version(None, db), MatchVersion::Semver("0.1.1".into())); + + release("0.5.1+zstd.1.4.4", db); + assert_eq!(version(None, db), MatchVersion::Semver("0.5.1+zstd.1.4.4".into())); + assert_eq!(version(Some("0.5"), db), MatchVersion::Semver("0.5.1+zstd.1.4.4".into())); + assert_eq!(version(Some("0.5.1+zstd.1.4.4"), db), MatchVersion::Exact("0.5.1+zstd.1.4.4".into())); + + Ok(()) + }); + } }