summaryrefslogtreecommitdiffstats
path: root/src/package/dependency
diff options
context:
space:
mode:
Diffstat (limited to 'src/package/dependency')
-rw-r--r--src/package/dependency/build.rs148
-rw-r--r--src/package/dependency/condition.rs420
-rw-r--r--src/package/dependency/mod.rs2
-rw-r--r--src/package/dependency/runtime.rs193
4 files changed, 748 insertions, 15 deletions
diff --git a/src/package/dependency/build.rs b/src/package/dependency/build.rs
index 8eb8eb3..4d51335 100644
--- a/src/package/dependency/build.rs
+++ b/src/package/dependency/build.rs
@@ -12,30 +12,164 @@ use anyhow::Result;
use serde::Deserialize;
use serde::Serialize;
-use crate::package::dependency::ParseDependency;
-use crate::package::dependency::StringEqual;
use crate::package::PackageName;
use crate::package::PackageVersionConstraint;
+use crate::package::dependency::ParseDependency;
+use crate::package::dependency::StringEqual;
+use crate::package::dependency::condition::Condition;
/// A dependency that is packaged and is only required during build time
#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
-#[serde(transparent)]
-pub struct BuildDependency(String);
+#[serde(untagged)]
+pub enum BuildDependency {
+ Simple(String),
+ Conditional {
+ name: String,
+ condition: Condition,
+ },
+}
impl AsRef<str> for BuildDependency {
fn as_ref(&self) -> &str {
- self.0.as_ref()
+ match self {
+ BuildDependency::Simple(name) => name,
+ BuildDependency::Conditional { name, .. } => name,
+ }
}
}
impl StringEqual for BuildDependency {
fn str_equal(&self, s: &str) -> bool {
- self.0 == s
+ match self {
+ BuildDependency::Simple(name) => name == s,
+ BuildDependency::Conditional { name, .. } => name == s,
+ }
}
}
impl ParseDependency for BuildDependency {
fn parse_as_name_and_version(&self) -> Result<(PackageName, PackageVersionConstraint)> {
- crate::package::dependency::parse_package_dependency_string_into_name_and_version(&self.0)
+ crate::package::dependency::parse_package_dependency_string_into_name_and_version(self.as_ref())
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::package::dependency::condition::OneOrMore;
+
+ #[derive(serde::Serialize, serde::Deserialize)]
+ #[allow(unused)]
+ pub struct TestSetting {
+ setting: BuildDependency,
+ }
+
+ #[test]
+ fn test_parse_dependency() {
+ let s: TestSetting = toml::from_str(r#"setting = "foo""#).expect("Parsing TestSetting failed");
+ match s.setting {
+ BuildDependency::Simple(name) => assert_eq!(name, "foo", "Expected 'foo', got {}", name),
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+
+ #[test]
+ fn test_parse_conditional_dependency() {
+ let s: TestSetting = toml::from_str(r#"setting = { name = "foo", condition = { in_image = "bar"} }"#).expect("Parsing TestSetting failed");
+ match s.setting {
+ BuildDependency::Conditional { name, condition } => {
+ assert_eq!(name, "foo", "Expected 'foo', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("bar"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+
+ #[test]
+ fn test_parse_conditional_dependency_pretty() {
+ let pretty = r#"
+ [setting]
+ name = "foo"
+ [setting.condition]
+ in_image = "bar"
+ "#;
+
+ let s: TestSetting = toml::from_str(pretty).expect("Parsing TestSetting failed");
+
+ match s.setting {
+ BuildDependency::Conditional { name, condition } => {
+ assert_eq!(name, "foo", "Expected 'foo', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("bar"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+
+
+ #[derive(serde::Serialize, serde::Deserialize)]
+ #[allow(unused)]
+ pub struct TestSettings {
+ settings: Vec<BuildDependency>,
+ }
+
+ #[test]
+ fn test_parse_conditional_dependencies() {
+ let s: TestSettings = toml::from_str(r#"settings = [{ name = "foo", condition = { in_image = "bar"} }]"#).expect("Parsing TestSetting failed");
+ match s.settings.get(0).expect("Has not one dependency") {
+ BuildDependency::Conditional { name, condition } => {
+ assert_eq!(name, "foo", "Expected 'foo', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("bar"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+
+ #[test]
+ fn test_parse_conditional_dependencies_pretty() {
+ let pretty = r#"
+ [[settings]]
+ name = "foo"
+ condition = { in_image = "bar" }
+ "#;
+
+ let s: TestSettings = toml::from_str(pretty).expect("Parsing TestSetting failed");
+
+ match s.settings.get(0).expect("Has not one dependency") {
+ BuildDependency::Conditional { name, condition } => {
+ assert_eq!(name, "foo", "Expected 'foo', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("bar"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+
+ #[test]
+ fn test_parse_conditional_dependencies_pretty_2() {
+ let pretty = r#"
+ [[settings]]
+ name = "foo"
+ condition.in_image = "bar"
+ "#;
+
+ let s: TestSettings = toml::from_str(pretty).expect("Parsing TestSetting failed");
+
+ match s.settings.get(0).expect("Has not one dependency") {
+ BuildDependency::Conditional { name, condition } => {
+ assert_eq!(name, "foo", "Expected 'foo', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("bar"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+}
+
diff --git a/src/package/dependency/condition.rs b/src/package/dependency/condition.rs
new file mode 100644
index 0000000..c39ece6
--- /dev/null
+++ b/src/package/dependency/condition.rs
@@ -0,0 +1,420 @@
+//
+// Copyright (c) 2020-2021 science+computing ag and other contributors
+//
+// This program and the accompanying materials are made
+// available under the terms of the Eclipse Public License 2.0
+// which is available at https://www.eclipse.org/legal/epl-2.0/
+//
+// SPDX-License-Identifier: EPL-2.0
+//
+
+use std::collections::BTreeMap;
+
+use serde::Deserialize;
+use serde::Serialize;
+use getset::Getters;
+use anyhow::Result;
+
+use crate::util::EnvironmentVariableName;
+use crate::util::docker::ImageName;
+
+/// The Condition type
+///
+/// This type represents a condition whether a dependency should be included in the package tree or
+/// not.
+///
+/// Right now, we are supporting condition by environment (set or equal) or whether a specific
+/// build image is used.
+/// All these settings are optional, of course.
+///
+#[derive(Serialize, Deserialize, Getters, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct Condition {
+ #[serde(rename = "has_env", skip_serializing_if = "Option::is_none")]
+ #[getset(get = "pub")]
+ pub(super) has_env: Option<OneOrMore<EnvironmentVariableName>>,
+
+ #[serde(rename = "env_eq", skip_serializing_if = "Option::is_none")]
+ #[getset(get = "pub")]
+ pub(super) env_eq: Option<BTreeMap<EnvironmentVariableName, String>>,
+
+ #[serde(rename = "in_image", skip_serializing_if = "Option::is_none")]
+ #[getset(get = "pub")]
+ pub(super) in_image: Option<OneOrMore<String>>,
+}
+
+impl Condition {
+ #[cfg(test)]
+ pub fn new(has_env: Option<OneOrMore<EnvironmentVariableName>>,
+ env_eq: Option<BTreeMap<EnvironmentVariableName, String>>,
+ in_image: Option<OneOrMore<String>>)
+ -> Self
+ {
+ Condition { has_env, env_eq, in_image }
+ }
+
+ /// Check whether the condition matches a certain set of data
+ ///
+ /// # Return value
+ ///
+ /// Always returns Ok(_) in the current implementation
+ pub fn matches(&self, data: &ConditionData<'_>) -> Result<bool> {
+ if !self.matches_env_cond(data)? {
+ return Ok(false)
+ }
+
+ if !self.matches_env_eq_cond(data)? {
+ return Ok(false)
+ }
+
+ if !self.matches_in_image_cond(data)? {
+ return Ok(false)
+ }
+
+ Ok(true)
+ }
+
+ fn matches_env_cond(&self, data: &ConditionData<'_>) -> Result<bool> {
+ if let Some(has_env_cond) = self.has_env.as_ref() {
+ let b = match has_env_cond {
+ OneOrMore::One(env) => data.env.iter().any(|(name, _)| env == name),
+ OneOrMore::More(envs) => envs.iter().all(|required_env| {
+ data.env
+ .iter()
+ .any(|(name, _)| name == required_env)
+ })
+ };
+
+ if !b {
+ return Ok(false)
+ }
+ }
+
+ Ok(true)
+ }
+
+ fn matches_env_eq_cond(&self, data: &ConditionData<'_>) -> Result<bool> {
+ if let Some(env_eq_cond) = self.env_eq.as_ref() {
+ let b = env_eq_cond.iter()
+ .all(|(req_env_name, req_env_val)| {
+ data.env
+ .iter()
+ .find(|(env_name, _)| env_name == req_env_name)
+ .map(|(_, env_val)| env_val == req_env_val)
+ .unwrap_or(false)
+ });
+
+ if !b {
+ return Ok(false)
+ }
+ }
+
+ Ok(true)
+ }
+
+ fn matches_in_image_cond(&self, data: &ConditionData<'_>) -> Result<bool> {
+ if let Some(in_image_cond) = self.in_image.as_ref() {
+ let b = match in_image_cond {
+ OneOrMore::One(req_image) => {
+ // because the image_name in the ConditionData is Option,
+ // which is a design-decision because the image can be not-specified (in the
+ // "tree-of" subcommand),
+ // we automatically use `false` as value here.
+ //
+ // That is because if we need to have a certain image (which is what this
+ // condition expresses), and there is no image specified in the ConditionData,
+ // we are by definition are NOT in this image.
+ data.image_name
+ .as_ref()
+ .map(|i| i.as_ref() == req_image)
+ .unwrap_or(false)
+ },
+ OneOrMore::More(req_images) => {
+ req_images.iter()
+ .any(|ri| {
+ data.image_name
+ .as_ref()
+ .map(|inam| inam.as_ref() == ri)
+ .unwrap_or(false)
+ })
+ },
+ };
+
+ Ok(b)
+ } else {
+ Ok(true)
+ }
+ }
+}
+
+
+/// Helper type for supporting Vec<T> and T in value
+/// position of Condition
+#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
+#[serde(untagged)]
+pub enum OneOrMore<T: Sized> {
+ One(T),
+ More(Vec<T>),
+}
+
+#[allow(clippy::from_over_into)]
+impl<T: Sized> Into<Vec<T>> for OneOrMore<T> {
+ fn into(self) -> Vec<T> {
+ match self {
+ OneOrMore::One(o) => vec![o],
+ OneOrMore::More(m) => m,
+ }
+ }
+}
+
+#[cfg(test)]
+impl From<Vec<String>> for OneOrMore<String> {
+ fn from(v: Vec<String>) -> Self {
+ OneOrMore::More(v)
+ }
+}
+
+#[cfg(test)]
+impl From<String> for OneOrMore<String> {
+ fn from(s: String) -> Self {
+ OneOrMore::One(s)
+ }
+}
+
+
+#[derive(Debug)]
+pub struct ConditionData<'a> {
+ pub(crate) image_name: Option<&'a ImageName>,
+ pub(crate) env: &'a [(EnvironmentVariableName, String)],
+}
+
+/// Trait for all things that have a condition that can be checked against ConditionData.
+///
+/// To be implemented by dependency types.
+///
+/// # Return value
+///
+/// Ok(true) if the dependency is relevant, considering the ConditionData
+/// Ok(false) if the dependency should be ignored, considering the ConditionData
+/// Err(_) if the condition checking failed (see `Condition::matches`)
+///
+pub trait ConditionCheckable {
+ fn check_condition(&self, data: &ConditionData<'_>) -> Result<bool>;
+}
+
+impl ConditionCheckable for crate::package::BuildDependency {
+ fn check_condition(&self, data: &ConditionData<'_>) -> Result<bool> {
+ match self {
+ // If the dependency is a simple one, e.g. "foo =1.2.3", there is no condition, so the
+ // dependency has always to be used
+ crate::package::BuildDependency::Simple(_) => Ok(true),
+ crate::package::BuildDependency::Conditional { condition, .. } => condition.matches(data),
+ }
+ }
+}
+
+impl ConditionCheckable for crate::package::Dependency {
+ fn check_condition(&self, data: &ConditionData<'_>) -> Result<bool> {
+ match self {
+ // If the dependency is a simple one, e.g. "foo =1.2.3", there is no condition, so the
+ // dependency has always to be used
+ crate::package::Dependency::Simple(_) => Ok(true),
+ crate::package::Dependency::Conditional { condition, .. } => condition.matches(data),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_has_env_deserialization() {
+ let s = r#"has_env = "foo""#;
+ let c: Condition = toml::from_str(s).expect("Deserializing has_env");
+
+ assert_eq!(c.has_env.unwrap(), OneOrMore::<EnvironmentVariableName>::One(EnvironmentVariableName::from("foo")));
+ assert!(c.env_eq.is_none());
+ assert!(c.in_image.is_none());
+ }
+
+ #[test]
+ fn test_has_env_list_deserialization() {
+ let s = r#"has_env = ["foo", "bar"]"#;
+ let c: Condition = toml::from_str(s).expect("Deserializing has_env");
+
+ assert_eq!(c.has_env.unwrap(), {
+ OneOrMore::<EnvironmentVariableName>::More({
+ vec![EnvironmentVariableName::from("foo"), EnvironmentVariableName::from("bar")]
+ })
+ });
+ assert!(c.env_eq.is_none());
+ assert!(c.in_image.is_none());
+ }
+
+ #[test]
+ fn test_env_eq_deserialization() {
+ let s = r#"env_eq = { "foo" = "bar" }"#;
+ let c: Condition = toml::from_str(s).expect("Deserializing has_env");
+
+ assert!(c.has_env.is_none());
+ assert_eq!(c.env_eq.unwrap(), {
+ let mut hm = BTreeMap::new();
+ hm.insert(EnvironmentVariableName::from("foo"), String::from("bar"));
+ hm
+ });
+ assert!(c.in_image.is_none());
+ }
+
+ #[test]
+ fn test_in_image_deserialization() {
+ let s = r#"in_image = "foo""#;
+ let c: Condition = toml::from_str(s).expect("Deserializing has_env");
+
+ assert!(c.has_env.is_none());
+ assert!(c.env_eq.is_none());
+ assert_eq!(c.in_image.unwrap(), OneOrMore::<String>::One(String::from("foo")));
+ }
+
+ #[test]
+ fn test_in_image_list_deserialization() {
+ let s = r#"in_image = ["foo"]"#;
+ let c: Condition = toml::from_str(s).expect("Deserializing has_env");
+
+ assert!(c.has_env.is_none());
+ assert!(c.env_eq.is_none());
+ assert_eq!(c.in_image.unwrap(), OneOrMore::<String>::More(vec![String::from("foo")]));
+ }
+
+ #[test]
+ fn test_condition_empty() {
+ let data = ConditionData {
+ image_name: None,
+ env: &[],
+ };
+
+ let condition = Condition::new(None, None, None);
+
+ assert!(condition.matches(&data).unwrap());
+ }
+
+ #[test]
+ fn test_condition_no_image() {
+ let data = ConditionData {
+ image_name: None,
+ env: &[],
+ };
+
+ let condition = Condition::new(None, None, {
+ Some(OneOrMore::<String>::One(String::from("req_image")))
+ });
+
+ assert!(!condition.matches(&data).unwrap());
+ }
+
+ #[test]
+ fn test_condition_matching_image() {
+ let img = ImageName::from("required_image");
+ let data = ConditionData {
+ image_name: Some(&img),
+ env: &[],
+ };
+
+ let condition = Condition::new(None, None, {
+ Some(OneOrMore::<String>::One(String::from("required_image")))
+ });
+
+ assert!(condition.matches(&data).unwrap());
+ }
+
+ #[test]
+ fn test_condition_nonmatching_image() {
+ let img = ImageName::from("required_image");
+ let data = ConditionData {
+ image_name: Some(&img),
+ env: &[],
+ };
+
+ let condition = Condition::new(None, None, {
+ Some(OneOrMore::<String>::One(String::from("other_image")))
+ });
+
+ assert!(!condition.matches(&data).unwrap());
+ }
+
+ #[test]
+ fn test_condition_required_env_missing() {
+ let data = ConditionData {
+ image_name: None,
+ env: &[],
+ };
+
+ let condition = Condition::new({
+ Some(OneOrMore::<EnvironmentVariableName>::One(EnvironmentVariableName::from("A")))
+ }, None, None);
+
+ assert!(!condition.matches(&data).unwrap());
+ }
+
+ #[test]
+ fn test_condition_required_env_present() {
+ let data = ConditionData {
+ image_name: None,
+ env: &[(EnvironmentVariableName::from("A"), String::from("1"))],
+ };
+
+ let condition = Condition::new({
+ Some(OneOrMore::<EnvironmentVariableName>::One(EnvironmentVariableName::from("A")))
+ }, None, None);
+
+ assert!(condition.matches(&data).unwrap());
+ }
+
+ #[test]
+ fn test_condition_required_env_values_missing() {
+ let data = ConditionData {
+ image_name: None,
+ env: &[],
+ };
+
+ let condition = Condition::new(None, {
+ let mut hm = BTreeMap::new();
+ hm.insert(EnvironmentVariableName::from("A"), String::from("1"));
+ Some(hm)
+ }, None);
+
+ assert!(!condition.matches(&data).unwrap());
+ }
+
+ #[test]
+ fn test_condition_required_env_values_present_but_different() {
+ let data = ConditionData {
+ image_name: None,
+ env: &[(EnvironmentVariableName::from("A"), String::from("1"))],
+ };
+
+ let condition = Condition::new(None, {
+ let mut hm = BTreeMap::new();
+ hm.insert(EnvironmentVariableName::from("A"), String::from("2"));
+ Some(hm)
+ }, None);
+
+ assert!(!condition.matches(&data).unwrap());
+ }
+
+ #[test]
+ fn test_condition_required_env_values_present_and_equal() {
+ let data = ConditionData {
+ image_name: None,
+ env: &[(EnvironmentVariableName::from("A"), String::from("1"))],
+ };
+
+ let condition = Condition::new(None, {
+ let mut hm = BTreeMap::new();
+ hm.insert(EnvironmentVariableName::from("A"), String::from("1"));
+ Some(hm)
+ }, None);
+
+ assert!(condition.matches(&data).unwrap());
+ }
+
+}
diff --git a/src/package/dependency/mod.rs b/src/package/dependency/mod.rs
index 37cb82b..da80a85 100644
--- a/src/package/dependency/mod.rs
+++ b/src/package/dependency/mod.rs
@@ -24,6 +24,8 @@ pub use build::*;
mod runtime;
pub use runtime::*;
+pub mod condition;
+
pub trait StringEqual {
fn str_equal(&self, s: &str) -> bool;
}
diff --git a/src/package/dependency/runtime.rs b/src/package/dependency/runtime.rs
index 62338ac..0a5b824 100644
--- a/src/package/dependency/runtime.rs
+++ b/src/package/dependency/runtime.rs
@@ -12,36 +12,213 @@ use anyhow::Result;
use serde::Deserialize;
use serde::Serialize;
-use crate::package::dependency::ParseDependency;
-use crate::package::dependency::StringEqual;
use crate::package::PackageName;
use crate::package::PackageVersionConstraint;
+use crate::package::dependency::ParseDependency;
+use crate::package::dependency::StringEqual;
+use crate::package::dependency::condition::Condition;
/// A dependency that is packaged and is required during runtime
#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
-#[serde(transparent)]
-pub struct Dependency(String);
+#[serde(untagged)]
+pub enum Dependency {
+ Simple(String),
+ Conditional {
+ name: String,
+ condition: Condition,
+ },
+}
+
+#[cfg(test)]
+impl Dependency {
+ pub fn new_conditional(name: String, condition: Condition) -> Self {
+ Dependency::Conditional { name, condition }
+ }
+}
impl AsRef<str> for Dependency {
fn as_ref(&self) -> &str {
- self.0.as_ref()
+ match self {
+ Dependency::Simple(name) => name,
+ Dependency::Conditional { name, .. } => name,
+ }
}
}
impl StringEqual for Dependency {
fn str_equal(&self, s: &str) -> bool {
- self.0 == s
+ match self {
+ Dependency::Simple(name) => name == s,
+ Dependency::Conditional { name, .. } => name == s,
+ }
}
}
impl From<String> for Dependency {
fn from(s: String) -> Dependency {
- Dependency(s)
+ Dependency::Simple(s)
}
}
impl ParseDependency for Dependency {
fn parse_as_name_and_version(&self) -> Result<(PackageName, PackageVersionConstraint)> {
- crate::package::dependency::parse_package_dependency_string_into_name_and_version(&self.0)
+ crate::package::dependency::parse_package_dependency_string_into_name_and_version(self.as_ref())
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::package::dependency::condition::OneOrMore;
+
+ #[derive(serde::Deserialize)]
+ #[allow(unused)]
+ pub struct TestSetting {
+ setting: Dependency,
+ }
+
+ #[test]
+ fn test_parse_dependency() {
+ let s: TestSetting = toml::from_str(r#"setting = "foo""#).expect("Parsing TestSetting failed");
+
+ match s.setting {
+ Dependency::Simple(name) => assert_eq!(name, "foo", "Expected 'foo', got {}", name),
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+
+ #[test]
+ fn test_parse_conditional_dependency() {
+ let s: TestSetting = toml::from_str(r#"setting = { name = "foo", condition = { in_image = "bar"} }"#).expect("Parsing TestSetting failed");
+ match s.setting {
+ Dependency::Conditional { name, condition } => {
+ assert_eq!(name, "foo", "Expected 'foo', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("bar"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+
+ #[test]
+ fn test_parse_conditional_dependency_pretty() {
+ let pretty = r#"
+ [setting]
+ name = "foo"
+ [setting.condition]
+ in_image = "bar"
+ "#;
+
+ let s: TestSetting = toml::from_str(pretty).expect("Parsing TestSetting failed");
+
+ match s.setting {
+ Dependency::Conditional { name, condition } => {
+ assert_eq!(name, "foo", "Expected 'foo', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("bar"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+
+
+ #[derive(serde::Serialize, serde::Deserialize)]
+ #[allow(unused)]
+ pub struct TestSettings {
+ settings: Vec<Dependency>,
+ }
+
+ #[test]
+ fn test_parse_conditional_dependencies() {
+ let s: TestSettings = toml::from_str(r#"settings = [{ name = "foo", condition = { in_image = "bar"} }]"#).expect("Parsing TestSetting failed");
+ match s.settings.get(0).expect("Has not one dependency") {
+ Dependency::Conditional { name, condition } => {
+ assert_eq!(name, "foo", "Expected 'foo', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("bar"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+
+ #[test]
+ fn test_parse_conditional_dependencies_pretty() {
+ let pretty = r#"
+ [[settings]]
+ name = "foo"
+ condition = { in_image = "bar" }
+ "#;
+
+ let s: TestSettings = toml::from_str(pretty).expect("Parsing TestSetting failed");
+
+ match s.settings.get(0).expect("Has not one dependency") {
+ Dependency::Conditional { name, condition } => {
+ assert_eq!(name, "foo", "Expected 'foo', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("bar"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+
+ #[test]
+ fn test_parse_conditional_dependencies_pretty_2() {
+ let pretty = r#"
+ [[settings]]
+ name = "foo"
+ condition.in_image = "bar"
+ "#;
+
+ let s: TestSettings = toml::from_str(pretty).expect("Parsing TestSetting failed");
+
+ match s.settings.get(0).expect("Has not one dependency") {
+ Dependency::Conditional { name, condition } => {
+ assert_eq!(name, "foo", "Expected 'foo', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("bar"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+
+ #[test]
+ fn test_parse_conditional_dependencies_pretty_3() {
+ let pretty = r#"
+ [[settings]]
+ name = "foo"
+ condition.in_image = "bar"
+
+ [[settings]]
+ name = "baz"
+ condition.in_image = "boogie"
+ "#;
+
+ let s: TestSettings = toml::from_str(pretty).expect("Parsing TestSetting failed");
+
+ match s.settings.get(0).expect("Has not one dependencies") {
+ Dependency::Conditional { name, condition } => {
+ assert_eq!(name, "foo", "Expected 'foo', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("bar"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+
+ match s.settings.get(1).expect("Has not two dependencies") {
+ Dependency::Conditional { name, condition } => {
+ assert_eq!(name, "baz", "Expected 'baz', got {}", name);
+ assert_eq!(*condition.has_env(), None);
+ assert_eq!(*condition.env_eq(), None);
+ assert_eq!(condition.in_image().as_ref(), Some(&OneOrMore::<String>::One(String::from("boogie"))));
+ },
+ other => panic!("Unexpected deserialization to other variant: {:?}", other),
+ }
+ }
+}
+