get_file_size/
get_file_size.rs

1// ---------------- [ File: get-file-size/src/get_file_size.rs ]
2crate::ix!();
3
4#[async_trait]
5pub trait GetFileSize {
6
7    async fn file_size(&self) -> Result<u64, FileError>;
8}
9
10#[async_trait]
11impl<T> GetFileSize for T
12where
13    T: AsRef<Path> + Send + Sync,
14{
15    async fn file_size(&self) -> Result<u64, FileError> {
16        Ok(tokio::fs::metadata(self.as_ref())
17            .await
18            .map_err(|e| FileError::GetMetadataError { io: e.into() })?
19            .len())
20    }
21}
22
23#[cfg(test)]
24mod test_get_file_size {
25    use super::*;
26    use std::io::Write as IoWrite;
27    use std::path::PathBuf;
28    use tempfile::{tempdir, NamedTempFile};
29    use tokio::fs::create_dir;
30    use tokio::io::AsyncWriteExt;
31
32    /// Verify that `file_size()` returns 0 for an empty file.
33    #[tokio::test]
34    async fn test_file_size_empty_file_returns_0() {
35        let temp_file = NamedTempFile::new().expect("Failed to create temp file");
36        let file_path = temp_file.path().to_path_buf();
37
38        let size = file_path.file_size().await;
39        assert!(size.is_ok(), "Expected Ok for empty file metadata");
40        assert_eq!(size.unwrap(), 0, "Empty file should have size 0");
41    }
42
43    /// Verify that `file_size()` returns correct file size for a file with content.
44    #[tokio::test]
45    async fn test_file_size_existing_file_with_content() {
46        let mut temp_file = NamedTempFile::new().expect("Failed to create temp file");
47        let file_path = temp_file.path().to_path_buf();
48
49        // Write some content
50        let content = b"Hello, world!";
51        temp_file
52            .write_all(content)
53            .expect("Failed to write content to temp file");
54
55        let size = file_path.file_size().await;
56        assert!(size.is_ok(), "Expected Ok for file with content");
57        assert_eq!(
58            size.unwrap() as usize,
59            content.len(),
60            "File size should match number of bytes written"
61        );
62    }
63
64    /// Verify that `file_size()` returns an error for a non-existent file.
65    #[tokio::test]
66    async fn test_file_size_non_existent_file_returns_error() {
67        let non_existent_path = PathBuf::from("this_file_does_not_exist.xyz");
68        let result = non_existent_path.file_size().await;
69        assert!(result.is_err(), "Expected an error for non-existent file");
70        match result {
71            Err(FileError::GetMetadataError { .. }) => {
72                // This is the expected variant
73            }
74            _ => panic!("Expected FileError::GetMetadataError for non-existent file"),
75        }
76    }
77
78    /// Verify behavior when calling `file_size()` on a directory.
79    /// Generally, metadata for directories is valid, and it returns a size (which may be 0 or OS-specific).
80    #[tokio::test]
81    async fn test_file_size_directory() {
82        let temp_dir = tempdir().expect("Failed to create temp directory");
83        let dir_path = temp_dir.path().to_path_buf();
84
85        let size = dir_path.file_size().await;
86        // Some filesystems set directory sizes to 0, others may set it to a block size, etc.
87        // So we won't test for an exact numeric size. We'll just check it's Ok and >= 0.
88        assert!(size.is_ok(), "Getting metadata for a directory should succeed on most platforms");
89        let size_val = size.unwrap();
90        assert!(
91            size_val >= 0,
92            "Directory size ({} bytes) should be non-negative",
93            size_val
94        );
95    }
96
97    /// (Optional) Test with a nested directory structure. Typically, the size might remain 0 or reflect
98    /// an internal structure, depending on the filesystem. 
99    #[tokio::test]
100    async fn test_file_size_nested_directory() {
101        let temp_dir = tempdir().expect("Failed to create temp directory");
102        let nested_dir = temp_dir.path().join("nested");
103        create_dir(&nested_dir).await.expect("Failed to create nested dir");
104
105        let size = nested_dir.file_size().await;
106        assert!(size.is_ok(), "Getting metadata for nested directory should succeed");
107    }
108
109    /// (Optional) Large file test. We create a file with a certain size and verify it.
110    /// For demonstration, we'll just do a slightly larger buffer (e.g., 1 MB). Adjust as needed.
111    #[tokio::test]
112    async fn test_file_size_large_file() {
113        let mut temp_file = NamedTempFile::new().expect("Failed to create temp file");
114        let file_path = temp_file.path().to_path_buf();
115
116        // Write 1 MB of data
117        let data_size = 1_000_000usize;
118        let data = vec![0u8; data_size];
119        temp_file
120            .write_all(&data)
121            .expect("Failed to write large data to temp file");
122
123        let size = file_path.file_size().await;
124        assert!(size.is_ok(), "Expected Ok for large file metadata");
125        assert_eq!(
126            size.unwrap() as usize,
127            data_size,
128            "File size should match 1 MB of data"
129        );
130    }
131}