From 7196452b23ec976a227e7254e4da3cfe2556e47c Mon Sep 17 00:00:00 2001 From: AdmiringWorm Date: Sat, 10 Apr 2021 17:52:42 +0200 Subject: [PATCH] feat(choco): add ability to update metadata with global metadata --- Cargo.lock | 2 + aer_data/Cargo.toml | 2 + aer_data/src/lib.rs | 11 + aer_data/src/metadata.rs | 13 +- aer_data/src/metadata/chocolatey.rs | 901 +++++++++++++++++++++++++++- aer_data/src/prelude.rs | 2 +- aer_license/src/lib.rs | 37 ++ 7 files changed, 960 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20a0fcf..c623870 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,6 +46,8 @@ version = "0.1.0" dependencies = [ "aer_license", "aer_version", + "lazy_static", + "rand 0.8.3", "rstest", "serde", "url", diff --git a/aer_data/Cargo.toml b/aer_data/Cargo.toml index a0db1bd..205cd40 100644 --- a/aer_data/Cargo.toml +++ b/aer_data/Cargo.toml @@ -19,6 +19,8 @@ url = "2.2.1" whoami = "1.1.2" [dev-dependencies] +lazy_static = "1.4.0" +rand = "0.8.3" rstest = "0.7.0" [package.metadata.docs.rs] diff --git a/aer_data/src/lib.rs b/aer_data/src/lib.rs index d2b541a..fa5df36 100644 --- a/aer_data/src/lib.rs +++ b/aer_data/src/lib.rs @@ -83,6 +83,17 @@ impl PackageData { } } +/// Implements a trait to use by updating necessary data +/// to a package specific handler. +pub trait DataUpdater { + /// Updates the current data with the data in the specified from argument. + fn update_from>(&mut self, from: R); + + /// Resets the current data by comparing it with the data in the specified + /// argument. + fn reset_same>(&mut self, from: R); +} + #[cfg(test)] mod tests { use super::*; diff --git a/aer_data/src/metadata.rs b/aer_data/src/metadata.rs index c52364e..03abc14 100644 --- a/aer_data/src/metadata.rs +++ b/aer_data/src/metadata.rs @@ -115,10 +115,10 @@ pub struct PackageMetadata { impl PackageMetadata { /// Creates a new instance of the package metadata with the specified /// identifier. - pub fn new(id: &str) -> PackageMetadata { + pub fn new>(id: T) -> PackageMetadata { PackageMetadata { package_source_url: None, - id: id.to_owned(), + id: id.as_ref().to_string(), maintainers: crate::defaults::maintainer(), summary: String::new(), project_url: crate::defaults::url(), @@ -174,6 +174,11 @@ impl PackageMetadata { &self.project_url } + /// Wether the project source url has been set or not. + pub fn has_project_source_url(&self) -> bool { + self.project_source_url.is_some() + } + /// The location where the source of the software is hosted. Can be a /// repository, or potentially a url to the location were source archives /// can be downloaded (not a direct url). @@ -223,8 +228,8 @@ impl PackageMetadata { /// Allows setting the url to the project (usually the home page of the /// software). Will return [url::ParseError] if the specified url is not /// a url. - pub fn set_project_url(&mut self, url: &str) { - let url = Url::parse(url).unwrap(); // We want a failure here to abort the program + pub fn set_project_url>(&mut self, url: U) { + let url = Url::parse(url.as_ref()).unwrap(); // We want a failure here to abort the program self.project_url = url; } diff --git a/aer_data/src/metadata/chocolatey.rs b/aer_data/src/metadata/chocolatey.rs index d70a490..cc7cd5e 100644 --- a/aer_data/src/metadata/chocolatey.rs +++ b/aer_data/src/metadata/chocolatey.rs @@ -18,6 +18,15 @@ use url::Url; use crate::prelude::*; +fn generate_identifier>(id: T, lowercase: bool) -> String { + if lowercase { + id.as_ref().to_lowercase() + } else { + id.as_ref().into() + } + .replace(' ', "-") +} + /// Basic structure to hold information regarding a /// package that are only specific to creating Chocolatey /// packages. @@ -58,7 +67,7 @@ pub struct ChocolateyMetadata { #[cfg_attr(feature = "serialize", serde(default))] id: String, - #[cfg_attr(feature = "serialize", serde(default = "crate::defaults::maintainer"))] + #[cfg_attr(feature = "serialize", serde(default))] maintainers: Vec, /// The short summary of the application, usually what is used as a @@ -372,6 +381,19 @@ impl ChocolateyMetadata { data } + + /// Creates a new instance with the specified identifier. + /// The identifier is expected to be a valid chocolatey id. + pub fn with_id>(id: T, lowercase: bool) -> Self { + let mut choco = ChocolateyMetadata { + lowercase_id: lowercase, + id: generate_identifier(id.as_ref(), lowercase), + ..Default::default() + }; + choco.add_tag(generate_identifier(id, true)); + + choco + } } impl Default for ChocolateyMetadata { @@ -388,7 +410,7 @@ impl Default for ChocolateyMetadata { ChocolateyMetadata { lowercase_id: true, id: Default::default(), - maintainers: crate::defaults::maintainer(), + maintainers: Vec::new(), summary: None, project_url: None, project_source_url: None, @@ -410,11 +432,216 @@ impl Default for ChocolateyMetadata { } } +impl DataUpdater for ChocolateyMetadata { + /// This task updates the [ChocolateyMetadata] with the necessary values + /// specified in the [PackageMetadata] structure. + /// + /// Among the tasks that are being done is as follows: + /// + /// - Updates the [id][Self::id] if it is an empty string with the value + /// specified in [PackageMetadata::id] while replacing spaces with dashes, + /// and makes it lowercase if [lowercase_id][Self::lowercase_id] is set to + /// `true`. + /// - Update the [maintainers][Self::id] if it is empty, or is equal to the + /// operating system user with the values from + /// [PackageMetadata::maintainers]. + /// - Update the [summary][Self::summary] if it is empty with the values + /// from [PackageMetadata::summary]. + /// - Update the [project_url][Self::project_url] if it is empty with the + /// values from [PackageMetadata::project_url]. + /// - Update the [project_source_url][Self::project_source_url] if it is + /// empty with the values from [PackageMetadata::project_source_url]. + /// - Update the [package_source_url][Self::package_source_url] if it is + /// empty with the values from [PackageMetadata::package_source_url]. + /// - Update the [license_url][Self::license_url] if it is empty with the + /// values from [PackageMetadata]::license_url. This will only be + /// automatically set if the global metadata also have a url specified, or + /// if the expression is a known/supported SPDIX. + /// - Add the recommended identifier (replacing spaces with dashes, and in + /// lowercase) as the first item in the tags vector. + fn update_from>(&mut self, from: R) { + let from = from.as_ref(); + if self.id.is_empty() && !from.id().is_empty() { + self.id = generate_identifier(from.id(), self.lowercase_id()); + } + + if self.maintainers.is_empty() { + self.maintainers = from.maintainers().iter().map(|m| m.to_string()).collect(); + } + + if self.summary.is_none() && !from.summary.is_empty() { + self.summary = Some(from.summary.clone()); + } + + if self.project_url.is_none() { + self.project_url = Some(from.project_url().clone()); + } + + if self.project_source_url.is_none() { + self.project_source_url = from.project_source_url.clone(); + } + + if self.package_source_url.is_none() { + self.package_source_url = from.package_source_url.clone(); + } + + if self.license_url.is_none() { + if let Some(license) = from.license().license_url() { + self.license_url = Some(Url::parse(license).unwrap()); + } + } + + let lower_id = self.id().to_lowercase(); + if !self.id().is_empty() && !self.tags.contains(&lower_id) { + self.tags.insert(0, self.id().to_lowercase()); + } + } + + /// Reset the variables that are the same, automatically set or not needed. + /// + /// Among the tasks that are being done is as follows: + /// + /// - Removes the [id][Self::id] if it matches the expected identifier that + /// would automatically be created (_depends on the + /// [lowercase_id][Self::lowercase_id] variable_). + /// - Remove the [maintainers][Self::maintainers] if they are the same as + /// the global [PackageMetadata::maintainers] variable. + /// - Remove the [summary][Self::summary] if it is the same as the global + /// [PackageMetadata::summary] variable. + /// - Remove the [project_url][Self::project_url] if it is the same as the + /// global [PackageMetadata::project_url] variable. + /// - Remove the [project_source_url][Self::project_source_url] if it is the + /// same as the global [PackageMetadata::project_source_url] variable. + /// - Remove the [package_source_url][Self::package_source_url] if it is the + /// same as the global [PackageMetadata::package_source_url] variable. + /// - Remove the [license_url][Self::license_url] if it is the same as the + /// global [PackageMetadata::license] variable. + /// - Remove the tag matching the automatically generated identifier. + fn reset_same>(&mut self, from: R) { + let from = from.as_ref(); + let id = self.id().to_lowercase(); + if self.id() == generate_identifier(from.id(), self.lowercase_id()) { + self.id.clear(); + } + + if self.maintainers() == from.maintainers() { + self.maintainers.clear(); + } + + if let Some(ref summary) = self.summary { + if summary == &from.summary { + self.summary = None; + } + } + + if let Some(ref url) = self.project_url { + if url == &from.project_url { + self.project_url = None; + } + } + + if let Some(ref url) = self.project_source_url { + if url == from.project_source_url().as_ref() { + self.project_source_url = None; + } + } + + if let Some(ref url) = self.package_source_url { + if url == from.package_source_url().as_ref() { + self.package_source_url = None; + } + } + + if let Some(ref url) = self.license_url { + if let Some(license_url) = from.license().license_url() { + if url.as_ref() == license_url { + self.license_url = None; + } + } + } + + self.tags.retain(|t| t != &id); + } +} + #[cfg(test)] mod tests { + use lazy_static::lazy_static; + use rand::distributions::Alphanumeric; + use rand::prelude::*; + use super::*; + const IDENTIFIER_NAMES: &[&str] = &[ + "7Zip", + "CCleaner", + "Google Chrome", + "Firefox", + "Chocolatey", + "Pacman", + "AER", + "AU", + "CCVARN", + "GitReleaseManager", + ]; + + const MAINTAINERS: &[&str] = &[ + "AdmiringWorm", + "gep13", + "pauby", + "chtof", + "majkinetor", + "mkevenaar", + "ferventcoder", + "TheCakeIsNaOH", + "virtualex", + ]; + + const SPDIXES: &[&str] = &[ + "ADSL", + "AGPL-1.0-only", + "AGPL-3.0", + "Apache-1.0", + "Apache-2.0", + "BSD-4-Clause", + "CAL-1.0", + "CC-BY-SA-4.0", + "GPL-1.0+", + "GPL-2.0+", + "GPL-3.0", + "GPL-3.0+", + "GPL-3.0-only", + "GPL-3.0-with-GCC-exception", + "MIT-0", + "SSH-OpenSSH", + ]; + + lazy_static! { + static ref URLS: Vec = vec![ + Url::parse("https://chocolatey.org").unwrap(), + Url::parse("https://github.com").unwrap(), + Url::parse("https://github.com/WormieCorp/aer").unwrap(), + Url::parse("https://bitbucket.org").unwrap() + ]; + } + + fn get_maintainers(rng: &mut ThreadRng) -> Vec<&str> { + let mnum = rng.gen_range(1..MAINTAINERS.len()); + get_maintainers_num(rng, mnum) + } + + fn get_maintainers_num(rng: &mut ThreadRng, num: usize) -> Vec<&str> { + MAINTAINERS.choose_multiple(rng, num).map(|m| *m).collect() + } + + fn get_rand_alphanum(rng: &mut ThreadRng, len: usize) -> String { + rng.sample_iter(Alphanumeric) + .take(len) + .map(char::from) + .collect() + } + #[test] fn new_should_create_with_expected_values() { let expected = ChocolateyMetadata::default(); @@ -429,7 +656,7 @@ mod tests { let expected = ChocolateyMetadata { lowercase_id: true, id: String::new(), - maintainers: crate::defaults::maintainer(), + maintainers: Vec::new(), summary: None, project_url: None, project_source_url: None, @@ -520,4 +747,672 @@ mod tests { assert_eq!(data.description(), "My awesome description"); } + + #[test] + fn update_from_should_set_lowercase_identifier() { + let mut rng = thread_rng(); + let id = *IDENTIFIER_NAMES.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::with_id(&id, true); + expected.project_url = Some(crate::defaults::url()); + let mut pkg = PackageMetadata::new(id); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_remove_same_lowercase_identifier() { + let mut rng = thread_rng(); + let id = *IDENTIFIER_NAMES.choose(&mut rng).unwrap(); + let expected = ChocolateyMetadata::default(); + let pkg = PackageMetadata::new(id); + + let mut actual = ChocolateyMetadata::with_id(id, true); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_set_expected_identifier_and_tag() { + let mut rng = thread_rng(); + let id = *IDENTIFIER_NAMES.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::with_id(&id, false); + expected.project_url = Some(crate::defaults::url()); + let mut pkg = PackageMetadata::new(id); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.lowercase_id = false; + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_remove_same_identifier_and_tag() { + let mut rng = thread_rng(); + let id = *IDENTIFIER_NAMES.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.lowercase_id = false; + let pkg = PackageMetadata::new(id); + + let mut actual = ChocolateyMetadata::with_id(id, false); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_not_remove_different_identifier() { + let mut rng = thread_rng(); + let id = *IDENTIFIER_NAMES.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::with_id(id, false); + let pkg = PackageMetadata::new("Test Id"); + + let mut actual = expected.clone(); + actual.reset_same(pkg); + expected.tags.clear(); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_not_replace_existing_identifier() { + let mut rng = thread_rng(); + let id = *IDENTIFIER_NAMES.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::with_id(&id, false); + expected.project_url = Some(crate::defaults::url()); + let mut pkg = PackageMetadata::new("Test value"); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::with_id(id, false); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_set_expected_maintainers() { + let mut rng = thread_rng(); + let maintainers = get_maintainers(&mut rng); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(crate::defaults::url()); + expected.maintainers = maintainers.iter().map(|m| m.to_string()).collect(); + let mut pkg = PackageMetadata::default(); + pkg.set_maintainers(&maintainers); + + let mut actual = ChocolateyMetadata::default(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_not_replace_existing_maintainers() { + let mut rng = thread_rng(); + let maintainers = get_maintainers(&mut rng); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(crate::defaults::url()); + expected.maintainers = maintainers.iter().map(|m| m.to_string()).collect(); + let mut pkg = PackageMetadata::default(); + pkg.set_maintainers(&["Test User 1", "Test User 2"]); + + let mut actual = expected.clone(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_remove_same_maintainers() { + let mut rng = thread_rng(); + let maintainers = get_maintainers(&mut rng); + let expected = ChocolateyMetadata::default(); + let mut pkg = PackageMetadata::default(); + pkg.set_maintainers(&maintainers); + + let mut actual = ChocolateyMetadata::default(); + actual.maintainers = pkg.maintainers.clone(); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_not_remove_different_maintainers() { + let mut rng = thread_rng(); + let maintainers = get_maintainers(&mut rng); + let mut expected = ChocolateyMetadata::default(); + expected.maintainers = maintainers.iter().map(|m| m.to_string()).collect(); + let mut pkg = PackageMetadata::default(); + pkg.set_maintainers(&["Test Maint 1", "Test Maint 2"]); + + let mut actual = expected.clone(); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_set_expected_summary() { + let mut rng = thread_rng(); + let summary = get_rand_alphanum(&mut rng, 50); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(crate::defaults::url()); + expected.summary = Some(summary.clone()); + let mut pkg = PackageMetadata::default(); + pkg.summary = summary; + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_not_set_empty_summary() { + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(crate::defaults::url()); + let mut pkg = PackageMetadata::default(); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_not_replace_existing_summary() { + let mut rng = thread_rng(); + let summary = get_rand_alphanum(&mut rng, 50); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(crate::defaults::url()); + expected.summary = Some(summary); + let mut pkg = PackageMetadata::default(); + pkg.summary = get_rand_alphanum(&mut rng, 40); + pkg.maintainers.clear(); + + let mut actual = expected.clone(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_remove_same_summary() { + let mut rng = thread_rng(); + let summary = get_rand_alphanum(&mut rng, 50); + let expected = ChocolateyMetadata::default(); + let mut pkg = PackageMetadata::default(); + pkg.summary = summary.clone(); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.summary = Some(summary); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_not_remove_different_summary() { + let mut rng = thread_rng(); + let mut expected = ChocolateyMetadata::default(); + expected.summary = Some(get_rand_alphanum(&mut rng, 40)); + let mut pkg = PackageMetadata::default(); + pkg.summary = get_rand_alphanum(&mut rng, 20); + pkg.maintainers.clear(); + + let mut actual = expected.clone(); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_set_expected_project_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(url.clone()); + let mut pkg = PackageMetadata::default(); + pkg.set_project_url(url); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_not_replace_existing_project_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(url.clone()); + let mut pkg = PackageMetadata::default(); + pkg.set_project_url("https://test-replace.not"); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.project_url = Some(url.clone()); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_remove_same_project_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let expected = ChocolateyMetadata::default(); + let mut pkg = PackageMetadata::default(); + pkg.set_project_url(url); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.project_url = Some(url.clone()); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_not_remove_different_project_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(url.clone()); + let mut pkg = PackageMetadata::default(); + pkg.set_project_url("https://test-replace.not"); + pkg.maintainers.clear(); + + let mut actual = expected.clone(); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_set_expected_project_source_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(crate::defaults::url()); + expected.project_source_url = Some(url.clone()); + let mut pkg = PackageMetadata::default(); + pkg.set_project_source_url(url).unwrap(); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_not_replace_existing_project_source_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.project_source_url = Some(url.clone()); + expected.project_url = Some(crate::defaults::url()); + let mut pkg = PackageMetadata::default(); + pkg.set_project_source_url("https://test-replace.not") + .unwrap(); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.project_source_url = Some(url.clone()); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_remove_same_project_source_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let expected = ChocolateyMetadata::default(); + let mut pkg = PackageMetadata::default(); + pkg.set_project_source_url(url).unwrap(); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.project_source_url = Some(url.clone()); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_not_remove_different_project_source_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.project_source_url = Some(url.clone()); + let mut pkg = PackageMetadata::default(); + pkg.set_project_source_url("https://test-replace.not") + .unwrap(); + pkg.maintainers.clear(); + + let mut actual = expected.clone(); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_set_expected_package_source_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(crate::defaults::url()); + expected.package_source_url = Some(url.clone()); + let mut pkg = PackageMetadata::default(); + pkg.set_package_source_url(url).unwrap(); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_not_replace_existing_package_source_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.package_source_url = Some(url.clone()); + expected.project_url = Some(crate::defaults::url()); + let mut pkg = PackageMetadata::default(); + pkg.set_package_source_url("https://test-replace.not") + .unwrap(); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.package_source_url = Some(url.clone()); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_remove_same_package_source_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let expected = ChocolateyMetadata::default(); + let mut pkg = PackageMetadata::default(); + pkg.set_package_source_url(url).unwrap(); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.package_source_url = Some(url.clone()); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_not_remove_different_package_source_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.package_source_url = Some(url.clone()); + let mut pkg = PackageMetadata::default(); + pkg.set_package_source_url("https://test-replace.not") + .unwrap(); + pkg.maintainers.clear(); + + let mut actual = expected.clone(); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_set_expected_license_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(crate::defaults::url()); + expected.license_url = Some(url.clone()); + let mut pkg = PackageMetadata::default(); + pkg.set_license(url); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_not_replace_existing_license_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.license_url = Some(url.clone()); + expected.project_url = Some(crate::defaults::url()); + let mut pkg = PackageMetadata::default(); + pkg.set_license("https://test-replace.not"); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.license_url = Some(url.clone()); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_remove_same_license_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let expected = ChocolateyMetadata::default(); + let mut pkg = PackageMetadata::default(); + pkg.set_license(url); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.license_url = Some(url.clone()); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_not_remove_different_license_url() { + let mut rng = thread_rng(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.license_url = Some(url.clone()); + let mut pkg = PackageMetadata::default(); + pkg.set_license("https://test-replace.not"); + pkg.maintainers.clear(); + + let mut actual = expected.clone(); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_set_expected_license_expression() { + let mut rng = thread_rng(); + let spdix = *SPDIXES.choose(&mut rng).unwrap(); + let url = Url::parse( + LicenseType::Expression(spdix.to_string()) + .license_url() + .unwrap(), + ) + .unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(crate::defaults::url()); + expected.license_url = Some(url); + let mut pkg = PackageMetadata::default(); + pkg.set_license(spdix); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_not_set_license_on_unsupported_expression() { + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(crate::defaults::url()); + let mut pkg = PackageMetadata::default(); + pkg.set_license("invalid-spdix"); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_not_replace_existing_license_expression() { + let mut rng = thread_rng(); + let spdix = *SPDIXES.choose(&mut rng).unwrap(); + let url = Url::parse( + LicenseType::Expression(spdix.to_string()) + .license_url() + .unwrap(), + ) + .unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.license_url = Some(url.clone()); + expected.project_url = Some(crate::defaults::url()); + let mut pkg = PackageMetadata::default(); + pkg.set_license(spdix); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.license_url = Some(url); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_remove_same_license_expression() { + let mut rng = thread_rng(); + let spdix = *SPDIXES.choose(&mut rng).unwrap(); + let url = Url::parse( + LicenseType::Expression(spdix.to_string()) + .license_url() + .unwrap(), + ) + .unwrap(); + let expected = ChocolateyMetadata::default(); + let mut pkg = PackageMetadata::default(); + pkg.set_license(spdix); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.license_url = Some(url); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_not_remove_different_license_expression() { + let mut rng = thread_rng(); + let spdix = *SPDIXES.choose(&mut rng).unwrap(); + let url = crate::defaults::url(); + let mut expected = ChocolateyMetadata::default(); + expected.license_url = Some(url); + let mut pkg = PackageMetadata::default(); + pkg.set_license(spdix); + pkg.maintainers.clear(); + + let mut actual = expected.clone(); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_set_expected_license_expression_and_location() { + let mut rng = thread_rng(); + let spdix = *SPDIXES.choose(&mut rng).unwrap(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.project_url = Some(crate::defaults::url()); + expected.license_url = Some(url.clone()); + let mut pkg = PackageMetadata::default(); + pkg.set_license((spdix, url)); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn update_from_should_not_replace_existing_license_expression_and_location() { + let mut rng = thread_rng(); + let spdix = *SPDIXES.choose(&mut rng).unwrap(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.license_url = Some(url.clone()); + expected.project_url = Some(crate::defaults::url()); + let mut pkg = PackageMetadata::default(); + pkg.set_license((spdix, url)); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.license_url = Some(url.clone()); + actual.update_from(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_remove_same_license_expression_and_location() { + let mut rng = thread_rng(); + let spdix = *SPDIXES.choose(&mut rng).unwrap(); + let url = URLS.choose(&mut rng).unwrap(); + let expected = ChocolateyMetadata::default(); + let mut pkg = PackageMetadata::default(); + pkg.set_license((spdix, url)); + pkg.maintainers.clear(); + + let mut actual = ChocolateyMetadata::default(); + actual.license_url = Some(url.clone()); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } + + #[test] + fn reset_same_should_not_remove_different_license_expression_and_location() { + let mut rng = thread_rng(); + let spdix = *SPDIXES.choose(&mut rng).unwrap(); + let url = URLS.choose(&mut rng).unwrap(); + let mut expected = ChocolateyMetadata::default(); + expected.license_url = Some(crate::defaults::url()); + let mut pkg = PackageMetadata::default(); + pkg.set_license((spdix, url)); + pkg.maintainers.clear(); + + let mut actual = expected.clone(); + actual.reset_same(pkg); + + assert_eq!(actual, expected); + } } diff --git a/aer_data/src/prelude.rs b/aer_data/src/prelude.rs index b8daa67..1c99ce5 100644 --- a/aer_data/src/prelude.rs +++ b/aer_data/src/prelude.rs @@ -9,7 +9,7 @@ pub use url::Url; pub use crate::metadata::{Description, PackageMetadata}; pub use crate::updater::PackageUpdateData; -pub use crate::PackageData; +pub use crate::{DataUpdater, PackageData}; /// Re-Exports of usable chocolatey types. #[cfg(feature = "chocolatey")] diff --git a/aer_license/src/lib.rs b/aer_license/src/lib.rs index 9a03ab5..499dab7 100644 --- a/aer_license/src/lib.rs +++ b/aer_license/src/lib.rs @@ -79,6 +79,43 @@ impl LicenseType { } } +impl From for LicenseType { + fn from(url: Url) -> Self { + LicenseType::Location(url) + } +} + +impl From<&Url> for LicenseType { + fn from(url: &Url) -> Self { + LicenseType::Location(url.clone()) + } +} + +impl From for LicenseType { + fn from(val: String) -> Self { + if let Ok(url) = Url::parse(&val) { + LicenseType::Location(url) + } else { + LicenseType::Expression(val) + } + } +} + +impl From<&str> for LicenseType { + fn from(val: &str) -> Self { + val.to_owned().into() + } +} + +impl From<(&str, &Url)> for LicenseType { + fn from(val: (&str, &Url)) -> Self { + LicenseType::ExpressionAndLocation { + expression: val.0.to_owned(), + url: val.1.to_owned(), + } + } +} + #[cfg(test)] mod tests { use rstest::rstest;