diff --git a/src/uu/tar/src/operations/create.rs b/src/uu/tar/src/operations/create.rs index 41923c9..01e53b8 100644 --- a/src/uu/tar/src/operations/create.rs +++ b/src/uu/tar/src/operations/create.rs @@ -156,80 +156,5 @@ fn normalize_path(path: &Path, allow_absolute: bool) -> Option { } #[cfg(test)] -mod tests { - use super::*; - use std::io::{self, Write}; - use tar::Archive; - use tempfile::{tempdir, TempDir}; - - struct FailFlushWriter; - impl Write for FailFlushWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Err(io::Error::other("flush failed")) - } - } - - #[test] - fn test_create_archive_flush_failed() { - let dir = TempDir::new().unwrap(); - let file_path = dir.path().join("test.txt"); - fs::write(&file_path, "hello").unwrap(); - - let output = FailFlushWriter; - let status_output = io::sink(); - - let res = create_archive( - output, - status_output, - &[file_path.as_path()], - false, - false, - CompressionMode::None, - ); - assert!(res.is_err()); - } - - #[test] - fn test_create_archive_with_zstd() { - let tempdir = tempdir().unwrap(); - let _guard = crate::operations::TestDirGuard::enter(tempdir.path()); - fs::write("file.txt", "hello").unwrap(); - - create_archive( - fs::File::create("archive.tar.zst").unwrap(), - io::sink(), - &[Path::new("file.txt")], - false, - false, - CompressionMode::Zstd, - ) - .unwrap(); - - let decoder = - zstd::stream::read::Decoder::new(fs::File::open("archive.tar.zst").unwrap()).unwrap(); - let mut archive = Archive::new(decoder); - let mut entries = archive.entries().unwrap(); - let entry = entries.next().unwrap().unwrap(); - assert_eq!(entry.path().unwrap().to_str(), Some("file.txt")); - } - - #[test] - fn test_create_archive_missing_file_fails() { - let tempdir = tempdir().unwrap(); - let missing_path = tempdir.path().join("missing.txt"); - - let err = create_archive( - io::sink(), - io::sink(), - &[missing_path.as_path()], - false, - false, - CompressionMode::Zstd, - ) - .unwrap_err(); - assert!(err.to_string().contains("missing.txt")); - } -} +#[path = "create_tests.rs"] +mod tests; diff --git a/src/uu/tar/src/operations/create_tests.rs b/src/uu/tar/src/operations/create_tests.rs new file mode 100644 index 0000000..631ffee --- /dev/null +++ b/src/uu/tar/src/operations/create_tests.rs @@ -0,0 +1,80 @@ +// This file is part of the uutils tar package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use super::*; +use std::io::{self, Write}; +use tar::Archive; +use tempfile::{tempdir, TempDir}; + +struct FailFlushWriter; +impl Write for FailFlushWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + fn flush(&mut self) -> io::Result<()> { + Err(io::Error::other("flush failed")) + } +} + +#[test] +fn test_create_archive_flush_failed() { + let dir = TempDir::new().unwrap(); + let file_path = dir.path().join("test.txt"); + fs::write(&file_path, "hello").unwrap(); + + let output = FailFlushWriter; + let status_output = io::sink(); + + let res = create_archive( + output, + status_output, + &[file_path.as_path()], + false, + false, + CompressionMode::None, + ); + assert!(res.is_err()); +} + +#[test] +fn test_create_archive_with_zstd() { + let tempdir = tempdir().unwrap(); + let _guard = crate::operations::TestDirGuard::enter(tempdir.path()); + fs::write("file.txt", "hello").unwrap(); + + create_archive( + fs::File::create("archive.tar.zst").unwrap(), + io::sink(), + &[Path::new("file.txt")], + false, + false, + CompressionMode::Zstd, + ) + .unwrap(); + + let decoder = + zstd::stream::read::Decoder::new(fs::File::open("archive.tar.zst").unwrap()).unwrap(); + let mut archive = Archive::new(decoder); + let mut entries = archive.entries().unwrap(); + let entry = entries.next().unwrap().unwrap(); + assert_eq!(entry.path().unwrap().to_str(), Some("file.txt")); +} + +#[test] +fn test_create_archive_missing_file_fails() { + let tempdir = tempdir().unwrap(); + let missing_path = tempdir.path().join("missing.txt"); + + let err = create_archive( + io::sink(), + io::sink(), + &[missing_path.as_path()], + false, + false, + CompressionMode::Zstd, + ) + .unwrap_err(); + assert!(err.to_string().contains("missing.txt")); +} diff --git a/src/uu/tar/src/operations/extract.rs b/src/uu/tar/src/operations/extract.rs index e805a47..7c707c6 100644 --- a/src/uu/tar/src/operations/extract.rs +++ b/src/uu/tar/src/operations/extract.rs @@ -65,41 +65,5 @@ pub fn extract_archive( } #[cfg(test)] -mod tests { - use super::*; - use crate::CompressionMode; - use std::fs; - use tar::Builder; - use tempfile::tempdir; - - #[test] - fn test_extract_archive_with_zstd() { - let tempdir = tempdir().unwrap(); - let archive_path = tempdir.path().join("archive.tar.zst"); - - let mut tar_bytes = Vec::new(); - { - let mut builder = Builder::new(&mut tar_bytes); - let mut header = tar::Header::new_gnu(); - header.set_mode(0o644); - header.set_size("hello".len() as u64); - header.set_cksum(); - builder - .append_data(&mut header, "extracted.txt", std::io::Cursor::new("hello")) - .unwrap(); - builder.finish().unwrap(); - } - let compressed = zstd::stream::encode_all(std::io::Cursor::new(tar_bytes), 0).unwrap(); - fs::write(&archive_path, compressed).unwrap(); - - let _guard = crate::operations::TestDirGuard::enter(tempdir.path()); - let input = fs::File::open(&archive_path).unwrap(); - let result = extract_archive(input, &archive_path, true, CompressionMode::Zstd); - - result.unwrap(); - assert_eq!( - fs::read_to_string(tempdir.path().join("extracted.txt")).unwrap(), - "hello" - ); - } -} +#[path = "extract_tests.rs"] +mod tests; diff --git a/src/uu/tar/src/operations/extract_tests.rs b/src/uu/tar/src/operations/extract_tests.rs new file mode 100644 index 0000000..898caff --- /dev/null +++ b/src/uu/tar/src/operations/extract_tests.rs @@ -0,0 +1,41 @@ +// This file is part of the uutils tar package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use super::*; +use crate::CompressionMode; +use std::fs; +use tar::Builder; +use tempfile::tempdir; + +#[test] +fn test_extract_archive_with_zstd() { + let tempdir = tempdir().unwrap(); + let archive_path = tempdir.path().join("archive.tar.zst"); + + let mut tar_bytes = Vec::new(); + { + let mut builder = Builder::new(&mut tar_bytes); + let mut header = tar::Header::new_gnu(); + header.set_mode(0o644); + header.set_size("hello".len() as u64); + header.set_cksum(); + builder + .append_data(&mut header, "extracted.txt", std::io::Cursor::new("hello")) + .unwrap(); + builder.finish().unwrap(); + } + let compressed = zstd::stream::encode_all(std::io::Cursor::new(tar_bytes), 0).unwrap(); + fs::write(&archive_path, compressed).unwrap(); + + let _guard = crate::operations::TestDirGuard::enter(tempdir.path()); + let input = fs::File::open(&archive_path).unwrap(); + let result = extract_archive(input, &archive_path, true, CompressionMode::Zstd); + + result.unwrap(); + assert_eq!( + fs::read_to_string(tempdir.path().join("extracted.txt")).unwrap(), + "hello" + ); +} diff --git a/src/uu/tar/src/operations/list.rs b/src/uu/tar/src/operations/list.rs index 162711c..227cbe4 100644 --- a/src/uu/tar/src/operations/list.rs +++ b/src/uu/tar/src/operations/list.rs @@ -93,47 +93,5 @@ pub fn list_archive( } #[cfg(test)] -mod tests { - use super::*; - use crate::CompressionMode; - use std::fs; - use tar::Builder; - use tempfile::tempdir; - - fn write_zstd_tar(archive_path: &Path) { - let mut tar_bytes = Vec::new(); - { - let mut builder = Builder::new(&mut tar_bytes); - let mut header = tar::Header::new_gnu(); - header.set_mode(0o644); - header.set_size("hello".len() as u64); - header.set_cksum(); - builder - .append_data(&mut header, "listed.txt", std::io::Cursor::new("hello")) - .unwrap(); - builder.finish().unwrap(); - } - let compressed = zstd::stream::encode_all(std::io::Cursor::new(tar_bytes), 0).unwrap(); - fs::write(archive_path, compressed).unwrap(); - } - - #[test] - fn test_list_archive_with_zstd_non_verbose() { - let tempdir = tempdir().unwrap(); - let archive_path = tempdir.path().join("archive.tar.zst"); - write_zstd_tar(&archive_path); - - let input = fs::File::open(&archive_path).unwrap(); - list_archive(input, &archive_path, false, CompressionMode::Zstd).unwrap(); - } - - #[test] - fn test_list_archive_with_zstd_verbose() { - let tempdir = tempdir().unwrap(); - let archive_path = tempdir.path().join("archive.tar.zst"); - write_zstd_tar(&archive_path); - - let input = fs::File::open(&archive_path).unwrap(); - list_archive(input, &archive_path, true, CompressionMode::Zstd).unwrap(); - } -} +#[path = "list_tests.rs"] +mod tests; diff --git a/src/uu/tar/src/operations/list_tests.rs b/src/uu/tar/src/operations/list_tests.rs new file mode 100644 index 0000000..0bdb442 --- /dev/null +++ b/src/uu/tar/src/operations/list_tests.rs @@ -0,0 +1,47 @@ +// This file is part of the uutils tar package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use super::*; +use crate::CompressionMode; +use std::fs; +use tar::Builder; +use tempfile::tempdir; + +fn write_zstd_tar(archive_path: &Path) { + let mut tar_bytes = Vec::new(); + { + let mut builder = Builder::new(&mut tar_bytes); + let mut header = tar::Header::new_gnu(); + header.set_mode(0o644); + header.set_size("hello".len() as u64); + header.set_cksum(); + builder + .append_data(&mut header, "listed.txt", std::io::Cursor::new("hello")) + .unwrap(); + builder.finish().unwrap(); + } + let compressed = zstd::stream::encode_all(std::io::Cursor::new(tar_bytes), 0).unwrap(); + fs::write(archive_path, compressed).unwrap(); +} + +#[test] +fn test_list_archive_with_zstd_non_verbose() { + let tempdir = tempdir().unwrap(); + let archive_path = tempdir.path().join("archive.tar.zst"); + write_zstd_tar(&archive_path); + + let input = fs::File::open(&archive_path).unwrap(); + list_archive(input, &archive_path, false, CompressionMode::Zstd).unwrap(); +} + +#[test] +fn test_list_archive_with_zstd_verbose() { + let tempdir = tempdir().unwrap(); + let archive_path = tempdir.path().join("archive.tar.zst"); + write_zstd_tar(&archive_path); + + let input = fs::File::open(&archive_path).unwrap(); + list_archive(input, &archive_path, true, CompressionMode::Zstd).unwrap(); +} diff --git a/src/uu/tar/src/tar.rs b/src/uu/tar/src/tar.rs index 2bd55ed..ddb5eca 100644 --- a/src/uu/tar/src/tar.rs +++ b/src/uu/tar/src/tar.rs @@ -279,159 +279,5 @@ pub fn uu_app() -> Command { } #[cfg(test)] -mod tests { - use super::*; - use std::ffi::OsString; - use std::fs; - use tempfile::tempdir; - - // --- is_posix_keystring --- - - #[test] - fn test_keystring_create() { - assert!(is_posix_keystring("c")); - assert!(is_posix_keystring("cf")); - assert!(is_posix_keystring("cvf")); - assert!(is_posix_keystring("cv")); - } - - #[test] - fn test_keystring_extract() { - assert!(is_posix_keystring("x")); - assert!(is_posix_keystring("xf")); - assert!(is_posix_keystring("xvf")); - } - - #[test] - fn test_keystring_rejects_dash_prefix() { - assert!(!is_posix_keystring("-c")); - assert!(!is_posix_keystring("-cf")); - assert!(!is_posix_keystring("-xvf")); - } - - #[test] - fn test_keystring_rejects_no_function_letter() { - // modifier-only strings are not valid keystrings - assert!(!is_posix_keystring("f")); - assert!(!is_posix_keystring("vf")); - assert!(!is_posix_keystring("v")); - } - - #[test] - fn test_keystring_rejects_invalid_chars() { - assert!(!is_posix_keystring("cz")); // 'z' is not a key char - assert!(!is_posix_keystring("c1")); // digits not allowed - assert!(!is_posix_keystring("archive.tar")); // typical filename - } - - #[test] - fn test_keystring_rejects_empty() { - assert!(!is_posix_keystring("")); - } - - // --- expand_posix_keystring --- - - fn osvec(v: &[&str]) -> Vec { - v.iter().map(std::ffi::OsString::from).collect() - } - - #[test] - fn test_expand_cf() { - let input = osvec(&["tar", "cf", "archive.tar", "file.txt"]); - let expected = osvec(&["tar", "-c", "-f", "archive.tar", "file.txt"]); - assert_eq!(expand_posix_keystring(input), expected); - } - - #[test] - fn test_expand_cvf() { - let input = osvec(&["tar", "cvf", "archive.tar", "file.txt"]); - let expected = osvec(&["tar", "-c", "-v", "-f", "archive.tar", "file.txt"]); - assert_eq!(expand_posix_keystring(input), expected); - } - - #[test] - fn test_expand_xf() { - let input = osvec(&["tar", "xf", "archive.tar"]); - let expected = osvec(&["tar", "-x", "-f", "archive.tar"]); - assert_eq!(expand_posix_keystring(input), expected); - } - - #[test] - fn test_expand_xvf() { - let input = osvec(&["tar", "xvf", "archive.tar"]); - let expected = osvec(&["tar", "-x", "-v", "-f", "archive.tar"]); - assert_eq!(expand_posix_keystring(input), expected); - } - - #[test] - fn test_expand_preserves_dash_prefix_args() { - // When args already use '-' prefixes, no expansion should occur - let input = osvec(&["tar", "-cvf", "archive.tar", "file.txt"]); - assert_eq!(expand_posix_keystring(input.clone()), input); - } - - #[test] - fn test_expand_f_before_files() { - // 'f' consumes only the archive name; remaining args are files - let input = osvec(&["tar", "cf", "archive.tar", "a.txt", "b.txt"]); - let expected = osvec(&["tar", "-c", "-f", "archive.tar", "a.txt", "b.txt"]); - assert_eq!(expand_posix_keystring(input), expected); - } - - #[test] - fn test_expand_function_letter_only() { - // No 'f' modifier: no archive consumed from file operands - let input = osvec(&["tar", "c", "file.txt"]); - let expected = osvec(&["tar", "-c", "file.txt"]); - assert_eq!(expand_posix_keystring(input), expected); - } - - #[test] - fn test_expand_cbf() { - let input = osvec(&["tar", "cbf", "20", "archive.tar", "file.txt"]); - let expected = osvec(&["tar", "-c", "-b", "20", "-f", "archive.tar", "file.txt"]); - assert_eq!(expand_posix_keystring(input), expected); - } - - #[test] - fn test_uumain_dispatches_zstd_create_list_extract() { - let tempdir = tempdir().unwrap(); - let _guard = crate::operations::TestDirGuard::enter(tempdir.path()); - fs::write("file.txt", "hello").unwrap(); - - let create_args = vec![ - OsString::from("test-bin"), - OsString::from("tar"), - OsString::from("--zstd"), - OsString::from("-cf"), - OsString::from("archive.tar.zst"), - OsString::from("file.txt"), - ]; - assert_eq!(uumain(create_args.into_iter()), 0); - - let list_args = vec![ - OsString::from("test-bin"), - OsString::from("tar"), - OsString::from("--zstd"), - OsString::from("-tf"), - OsString::from("archive.tar.zst"), - ]; - assert_eq!(uumain(list_args.into_iter()), 0); - - fs::remove_file("file.txt").unwrap(); - let extract_args = vec![ - OsString::from("test-bin"), - OsString::from("tar"), - OsString::from("--zstd"), - OsString::from("-xf"), - OsString::from("archive.tar.zst"), - ]; - let result = uumain(extract_args.into_iter()); - - assert_eq!(result, 0); - assert_eq!( - fs::read_to_string(tempdir.path().join("file.txt")).unwrap(), - "hello" - ); - } -} +#[path = "tar_tests.rs"] +mod tests; diff --git a/src/uu/tar/src/tar_tests.rs b/src/uu/tar/src/tar_tests.rs new file mode 100644 index 0000000..7c3af37 --- /dev/null +++ b/src/uu/tar/src/tar_tests.rs @@ -0,0 +1,159 @@ +// This file is part of the uutils tar package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use super::*; +use std::ffi::OsString; +use std::fs; +use tempfile::tempdir; + +// --- is_posix_keystring --- + +#[test] +fn test_keystring_create() { + assert!(is_posix_keystring("c")); + assert!(is_posix_keystring("cf")); + assert!(is_posix_keystring("cvf")); + assert!(is_posix_keystring("cv")); +} + +#[test] +fn test_keystring_extract() { + assert!(is_posix_keystring("x")); + assert!(is_posix_keystring("xf")); + assert!(is_posix_keystring("xvf")); +} + +#[test] +fn test_keystring_rejects_dash_prefix() { + assert!(!is_posix_keystring("-c")); + assert!(!is_posix_keystring("-cf")); + assert!(!is_posix_keystring("-xvf")); +} + +#[test] +fn test_keystring_rejects_no_function_letter() { + // modifier-only strings are not valid keystrings + assert!(!is_posix_keystring("f")); + assert!(!is_posix_keystring("vf")); + assert!(!is_posix_keystring("v")); +} + +#[test] +fn test_keystring_rejects_invalid_chars() { + assert!(!is_posix_keystring("cz")); // 'z' is not a key char + assert!(!is_posix_keystring("c1")); // digits not allowed + assert!(!is_posix_keystring("archive.tar")); // typical filename +} + +#[test] +fn test_keystring_rejects_empty() { + assert!(!is_posix_keystring("")); +} + +// --- expand_posix_keystring --- + +fn osvec(v: &[&str]) -> Vec { + v.iter().map(std::ffi::OsString::from).collect() +} + +#[test] +fn test_expand_cf() { + let input = osvec(&["tar", "cf", "archive.tar", "file.txt"]); + let expected = osvec(&["tar", "-c", "-f", "archive.tar", "file.txt"]); + assert_eq!(expand_posix_keystring(input), expected); +} + +#[test] +fn test_expand_cvf() { + let input = osvec(&["tar", "cvf", "archive.tar", "file.txt"]); + let expected = osvec(&["tar", "-c", "-v", "-f", "archive.tar", "file.txt"]); + assert_eq!(expand_posix_keystring(input), expected); +} + +#[test] +fn test_expand_xf() { + let input = osvec(&["tar", "xf", "archive.tar"]); + let expected = osvec(&["tar", "-x", "-f", "archive.tar"]); + assert_eq!(expand_posix_keystring(input), expected); +} + +#[test] +fn test_expand_xvf() { + let input = osvec(&["tar", "xvf", "archive.tar"]); + let expected = osvec(&["tar", "-x", "-v", "-f", "archive.tar"]); + assert_eq!(expand_posix_keystring(input), expected); +} + +#[test] +fn test_expand_preserves_dash_prefix_args() { + // When args already use '-' prefixes, no expansion should occur + let input = osvec(&["tar", "-cvf", "archive.tar", "file.txt"]); + assert_eq!(expand_posix_keystring(input.clone()), input); +} + +#[test] +fn test_expand_f_before_files() { + // 'f' consumes only the archive name; remaining args are files + let input = osvec(&["tar", "cf", "archive.tar", "a.txt", "b.txt"]); + let expected = osvec(&["tar", "-c", "-f", "archive.tar", "a.txt", "b.txt"]); + assert_eq!(expand_posix_keystring(input), expected); +} + +#[test] +fn test_expand_function_letter_only() { + // No 'f' modifier: no archive consumed from file operands + let input = osvec(&["tar", "c", "file.txt"]); + let expected = osvec(&["tar", "-c", "file.txt"]); + assert_eq!(expand_posix_keystring(input), expected); +} + +#[test] +fn test_expand_cbf() { + let input = osvec(&["tar", "cbf", "20", "archive.tar", "file.txt"]); + let expected = osvec(&["tar", "-c", "-b", "20", "-f", "archive.tar", "file.txt"]); + assert_eq!(expand_posix_keystring(input), expected); +} + +#[test] +fn test_uumain_dispatches_zstd_create_list_extract() { + let tempdir = tempdir().unwrap(); + let _guard = crate::operations::TestDirGuard::enter(tempdir.path()); + fs::write("file.txt", "hello").unwrap(); + + let create_args = vec![ + OsString::from("test-bin"), + OsString::from("tar"), + OsString::from("--zstd"), + OsString::from("-cf"), + OsString::from("archive.tar.zst"), + OsString::from("file.txt"), + ]; + assert_eq!(uumain(create_args.into_iter()), 0); + + let list_args = vec![ + OsString::from("test-bin"), + OsString::from("tar"), + OsString::from("--zstd"), + OsString::from("-tf"), + OsString::from("archive.tar.zst"), + ]; + assert_eq!(uumain(list_args.into_iter()), 0); + + fs::remove_file("file.txt").unwrap(); + let extract_args = vec![ + OsString::from("test-bin"), + OsString::from("tar"), + OsString::from("--zstd"), + OsString::from("-xf"), + OsString::from("archive.tar.zst"), + ]; + let result = uumain(extract_args.into_iter()); + + assert_eq!(result, 0); + assert_eq!( + fs::read_to_string(tempdir.path().join("file.txt")).unwrap(), + "hello" + ); +}