diff --git a/rust/src/treefile.rs b/rust/src/treefile.rs index 77cb5965c0..4396bdc91a 100644 --- a/rust/src/treefile.rs +++ b/rust/src/treefile.rs @@ -576,14 +576,14 @@ impl TreefileExternals { /// array elements. fn whitespace_split_packages(pkgs: &[String]) -> Vec { pkgs.iter() - .flat_map(|element| split_whitespace_unless_quote(element).map(String::from)) + .flat_map(|element| split_whitespace_unless_quoted(element).map(String::from)) .collect() } // Helper for whitespace_split_packages(). // Splits a String by whitespace unless substring is wrapped between single quotes -// and returns split Strings in an Iterator. -fn split_whitespace_unless_quote(element: &String) -> std::vec::IntoIter { +// and returns split Strings in an Iterator, with quoted packages first. +fn split_whitespace_unless_quoted(element: &String) -> impl Iterator { let mut quoted_pkgs: Vec = vec![]; let mut to_whitespace_split: Vec = vec![]; let mut start_index = 0; @@ -900,6 +900,7 @@ ref: "exampleos/x86_64/blah" packages: - foo bar - baz + - corge 'quuz >= 1.0' packages-x86_64: - grub2 grub2-tools packages-s390x: @@ -925,7 +926,7 @@ packages-s390x: treefile_parse_stream(utils::InputFormat::YAML, &mut input, Some(ARCH_X86_64)).unwrap(); treefile = treefile.substitute_vars().unwrap(); assert!(treefile.treeref.unwrap() == "exampleos/x86_64/blah"); - assert!(treefile.packages.unwrap().len() == 5); + assert!(treefile.packages.unwrap().len() == 7); } #[test] @@ -968,7 +969,7 @@ remove-files: treefile_parse_stream(utils::InputFormat::YAML, &mut input, None).unwrap(); treefile = treefile.substitute_vars().unwrap(); assert!(treefile.treeref.unwrap() == "exampleos/x86_64/blah"); - assert!(treefile.packages.unwrap().len() == 3); + assert!(treefile.packages.unwrap().len() == 5); } fn append_and_parse(append: &'static str) -> TreeComposeConfig { @@ -1168,7 +1169,7 @@ include: foo.yaml "#, ); let tf = new_test_treefile(workdir.path(), buf.as_str(), None)?; - assert!(tf.parsed.packages.unwrap().len() == 4); + assert!(tf.parsed.packages.unwrap().len() == 6); Ok(()) } @@ -1238,7 +1239,7 @@ etc-group-members: treefile_merge(&mut mid, &mut base); treefile_merge(&mut top, &mut mid); let tf = ⊤ - assert!(tf.packages.as_ref().unwrap().len() == 8); + assert!(tf.packages.as_ref().unwrap().len() == 10); assert!(tf.etc_group_members.as_ref().unwrap().len() == 2); let rojig = tf.rojig.as_ref().unwrap(); assert!(rojig.name == "exampleos"); @@ -1258,6 +1259,66 @@ etc-group-members: == "table" ); } + + #[test] + fn test_split_whitespace_unless_quoted() { + // test single quoted package + let single_quoted_pkg = String::from("'foobar >= 1.0'"); + let pkgs: Vec = split_whitespace_unless_quoted(&single_quoted_pkg).collect(); + assert_eq!("foobar >= 1.0", pkgs[0]); + + // test multiple quoted packages + let mult_quoted_pkg = String::from("'foobar >= 1.0' 'quuz < 0.5' 'corge > 2'"); + let pkgs: Vec = split_whitespace_unless_quoted(&mult_quoted_pkg).collect(); + assert_eq!("foobar >= 1.0", pkgs[0]); + assert_eq!("quuz < 0.5", pkgs[1]); + assert_eq!("corge > 2", pkgs[2]); + + // test single unquoted package + let single_unquoted_pkg = String::from("foobar"); + let pkgs: Vec = split_whitespace_unless_quoted(&single_unquoted_pkg).collect(); + assert_eq!("foobar", pkgs[0]); + + // test multiple unquoted packages + let mult_unquoted_pkg = String::from("foobar quuz corge"); + let pkgs: Vec = split_whitespace_unless_quoted(&mult_unquoted_pkg).collect(); + assert_eq!("foobar", pkgs[0]); + assert_eq!("quuz", pkgs[1]); + assert_eq!("corge", pkgs[2]); + + // test different orderings of mixed quoted and unquoted packages + let mix_quoted_unquoted_pkgs = String::from("'foobar >= 1.1' baz-package 'corge < 0.5'"); + let pkgs: Vec = split_whitespace_unless_quoted(&mix_quoted_unquoted_pkgs).collect(); + assert_eq!("foobar >= 1.1", pkgs[0]); + assert_eq!("corge < 0.5", pkgs[1]); + assert_eq!("baz-package", pkgs[2]); + let mix_quoted_unquoted_pkgs = String::from("corge 'foobar >= 1.1' baz-package"); + let pkgs: Vec = split_whitespace_unless_quoted(&mix_quoted_unquoted_pkgs).collect(); + assert_eq!("foobar >= 1.1", pkgs[0]); + assert_eq!("corge", pkgs[1]); + assert_eq!("baz-package", pkgs[2]); + let mix_quoted_unquoted_pkgs = + String::from("corge 'foobar >= 1.1' baz-package 'quuz < 0.0.1'"); + let pkgs: Vec = split_whitespace_unless_quoted(&mix_quoted_unquoted_pkgs).collect(); + assert_eq!("foobar >= 1.1", pkgs[0]); + assert_eq!("quuz < 0.0.1", pkgs[1]); + assert_eq!("corge", pkgs[2]); + assert_eq!("baz-package", pkgs[3]); + + // test missing quotes around packages using version qualifiers + let missing_quotes = String::from("foobar >= 1.0 quuz"); + let pkgs: Vec = split_whitespace_unless_quoted(&missing_quotes).collect(); + assert_ne!("foobar >= 1.0", pkgs[0]); + assert_eq!(">=", pkgs[1]); + let missing_leading_quote = String::from("foobar >= 1.0'"); + let pkgs: Vec = split_whitespace_unless_quoted(&missing_leading_quote).collect(); + assert_ne!("foobar >= 1.0", pkgs[0]); + assert_eq!(">=", pkgs[1]); + let missing_trailing_quote = String::from("'foobar >= 1.0 baz-package"); + let pkgs: Vec = split_whitespace_unless_quoted(&missing_trailing_quote).collect(); + assert_ne!("foobar >= 1.0", pkgs[0]); + assert_eq!(">=", pkgs[1]); + } } mod ffi { diff --git a/tests/compose/test-misc-tweaks.sh b/tests/compose/test-misc-tweaks.sh index fb6f7c4ad2..0afc8aa76f 100755 --- a/tests/compose/test-misc-tweaks.sh +++ b/tests/compose/test-misc-tweaks.sh @@ -187,4 +187,4 @@ if runcompose |& tee err.txt; then assert_not_reached "Successfully composed with add-files for /var/lib?" fi assert_file_has_content_literal err.txt "Unsupported path in add-files: /var" -echo "ok bad add-files" \ No newline at end of file +echo "ok bad add-files"