mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
Merge pull request #3176 from jfinkels/df-output-columns-2
df: implement the --output command-line argument
This commit is contained in:
commit
1795272473
4 changed files with 304 additions and 95 deletions
166
src/uu/df/src/columns.rs
Normal file
166
src/uu/df/src/columns.rs
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
// * This file is part of the uutils coreutils package.
|
||||||
|
// *
|
||||||
|
// * For the full copyright and license information, please view the LICENSE
|
||||||
|
// * file that was distributed with this source code.
|
||||||
|
// spell-checker:ignore itotal iused iavail ipcent pcent squashfs
|
||||||
|
use crate::{OPT_INODES, OPT_OUTPUT, OPT_PRINT_TYPE};
|
||||||
|
use clap::ArgMatches;
|
||||||
|
|
||||||
|
/// The columns in the output table produced by `df`.
|
||||||
|
///
|
||||||
|
/// The [`Row`] struct has a field corresponding to each of the
|
||||||
|
/// variants of this enumeration.
|
||||||
|
///
|
||||||
|
/// [`Row`]: crate::table::Row
|
||||||
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
|
pub(crate) enum Column {
|
||||||
|
/// The source of the mount point, usually a device.
|
||||||
|
Source,
|
||||||
|
|
||||||
|
/// Total number of blocks.
|
||||||
|
Size,
|
||||||
|
|
||||||
|
/// Number of used blocks.
|
||||||
|
Used,
|
||||||
|
|
||||||
|
/// Number of available blocks.
|
||||||
|
Avail,
|
||||||
|
|
||||||
|
/// Percentage of blocks used out of total number of blocks.
|
||||||
|
Pcent,
|
||||||
|
|
||||||
|
/// The mount point.
|
||||||
|
Target,
|
||||||
|
|
||||||
|
/// Total number of inodes.
|
||||||
|
Itotal,
|
||||||
|
|
||||||
|
/// Number of used inodes.
|
||||||
|
Iused,
|
||||||
|
|
||||||
|
/// Number of available inodes.
|
||||||
|
Iavail,
|
||||||
|
|
||||||
|
/// Percentage of inodes used out of total number of inodes.
|
||||||
|
Ipcent,
|
||||||
|
|
||||||
|
/// The filename given as a command-line argument.
|
||||||
|
File,
|
||||||
|
|
||||||
|
/// The filesystem type, like "ext4" or "squashfs".
|
||||||
|
Fstype,
|
||||||
|
|
||||||
|
/// Percentage of bytes available to non-privileged processes.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
Capacity,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Column {
|
||||||
|
/// Convert from command-line arguments to sequence of columns.
|
||||||
|
///
|
||||||
|
/// The set of columns that will appear in the output table can be
|
||||||
|
/// specified by command-line arguments. This function converts
|
||||||
|
/// those arguments to a [`Vec`] of [`Column`] variants.
|
||||||
|
pub(crate) fn from_matches(matches: &ArgMatches) -> Vec<Self> {
|
||||||
|
match (
|
||||||
|
matches.is_present(OPT_PRINT_TYPE),
|
||||||
|
matches.is_present(OPT_INODES),
|
||||||
|
matches.occurrences_of(OPT_OUTPUT) > 0,
|
||||||
|
) {
|
||||||
|
(false, false, false) => vec![
|
||||||
|
Self::Source,
|
||||||
|
Self::Size,
|
||||||
|
Self::Used,
|
||||||
|
Self::Avail,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
Self::Capacity,
|
||||||
|
Self::Pcent,
|
||||||
|
Self::Target,
|
||||||
|
],
|
||||||
|
(false, false, true) => {
|
||||||
|
matches
|
||||||
|
.values_of(OPT_OUTPUT)
|
||||||
|
.unwrap()
|
||||||
|
.map(|s| {
|
||||||
|
// Unwrapping here should not panic because the
|
||||||
|
// command-line argument parsing library should be
|
||||||
|
// responsible for ensuring each comma-separated
|
||||||
|
// string is a valid column label.
|
||||||
|
Self::parse(s).unwrap()
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
(false, true, false) => vec![
|
||||||
|
Self::Source,
|
||||||
|
Self::Itotal,
|
||||||
|
Self::Iused,
|
||||||
|
Self::Iavail,
|
||||||
|
Self::Ipcent,
|
||||||
|
Self::Target,
|
||||||
|
],
|
||||||
|
(true, false, false) => vec![
|
||||||
|
Self::Source,
|
||||||
|
Self::Fstype,
|
||||||
|
Self::Size,
|
||||||
|
Self::Used,
|
||||||
|
Self::Avail,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
Self::Capacity,
|
||||||
|
Self::Pcent,
|
||||||
|
Self::Target,
|
||||||
|
],
|
||||||
|
(true, true, false) => vec![
|
||||||
|
Self::Source,
|
||||||
|
Self::Fstype,
|
||||||
|
Self::Itotal,
|
||||||
|
Self::Iused,
|
||||||
|
Self::Iavail,
|
||||||
|
Self::Ipcent,
|
||||||
|
Self::Target,
|
||||||
|
],
|
||||||
|
// The command-line arguments -T and -i are each mutually
|
||||||
|
// exclusive with --output, so the command-line argument
|
||||||
|
// parser should reject those combinations before we get
|
||||||
|
// to this point in the code.
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a column name to the corresponding enumeration variant.
|
||||||
|
///
|
||||||
|
/// There are twelve valid column names, one for each variant:
|
||||||
|
///
|
||||||
|
/// - "source"
|
||||||
|
/// - "fstype"
|
||||||
|
/// - "itotal"
|
||||||
|
/// - "iused"
|
||||||
|
/// - "iavail"
|
||||||
|
/// - "ipcent"
|
||||||
|
/// - "size"
|
||||||
|
/// - "used"
|
||||||
|
/// - "avail"
|
||||||
|
/// - "pcent"
|
||||||
|
/// - "file"
|
||||||
|
/// - "target"
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If the string `s` is not one of the valid column names.
|
||||||
|
fn parse(s: &str) -> Result<Self, ()> {
|
||||||
|
match s {
|
||||||
|
"source" => Ok(Self::Source),
|
||||||
|
"fstype" => Ok(Self::Fstype),
|
||||||
|
"itotal" => Ok(Self::Itotal),
|
||||||
|
"iused" => Ok(Self::Iused),
|
||||||
|
"iavail" => Ok(Self::Iavail),
|
||||||
|
"ipcent" => Ok(Self::Ipcent),
|
||||||
|
"size" => Ok(Self::Size),
|
||||||
|
"used" => Ok(Self::Used),
|
||||||
|
"avail" => Ok(Self::Avail),
|
||||||
|
"pcent" => Ok(Self::Pcent),
|
||||||
|
"file" => Ok(Self::File),
|
||||||
|
"target" => Ok(Self::Target),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
// that was distributed with this source code.
|
// that was distributed with this source code.
|
||||||
// spell-checker:ignore itotal iused iavail ipcent pcent tmpfs squashfs
|
// spell-checker:ignore itotal iused iavail ipcent pcent tmpfs squashfs
|
||||||
mod blocks;
|
mod blocks;
|
||||||
|
mod columns;
|
||||||
mod table;
|
mod table;
|
||||||
|
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{UResult, USimpleError};
|
||||||
|
@ -25,6 +26,7 @@ use std::iter::FromIterator;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::blocks::{block_size_from_matches, BlockSize};
|
use crate::blocks::{block_size_from_matches, BlockSize};
|
||||||
|
use crate::columns::Column;
|
||||||
use crate::table::{DisplayRow, Header, Row};
|
use crate::table::{DisplayRow, Header, Row};
|
||||||
|
|
||||||
static ABOUT: &str = "Show information about the file system on which each FILE resides,\n\
|
static ABOUT: &str = "Show information about the file system on which each FILE resides,\n\
|
||||||
|
@ -66,18 +68,37 @@ struct FsSelector {
|
||||||
/// Most of these parameters control which rows and which columns are
|
/// Most of these parameters control which rows and which columns are
|
||||||
/// displayed. The `block_size` determines the units to use when
|
/// displayed. The `block_size` determines the units to use when
|
||||||
/// displaying numbers of bytes or inodes.
|
/// displaying numbers of bytes or inodes.
|
||||||
#[derive(Default)]
|
|
||||||
struct Options {
|
struct Options {
|
||||||
show_local_fs: bool,
|
show_local_fs: bool,
|
||||||
show_all_fs: bool,
|
show_all_fs: bool,
|
||||||
show_listed_fs: bool,
|
show_listed_fs: bool,
|
||||||
show_fs_type: bool,
|
|
||||||
show_inode_instead: bool,
|
|
||||||
block_size: BlockSize,
|
block_size: BlockSize,
|
||||||
fs_selector: FsSelector,
|
fs_selector: FsSelector,
|
||||||
|
|
||||||
/// Whether to show a final row comprising the totals for each column.
|
/// Whether to show a final row comprising the totals for each column.
|
||||||
show_total: bool,
|
show_total: bool,
|
||||||
|
/// Sequence of columns to display in the output table.
|
||||||
|
columns: Vec<Column>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Options {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
show_local_fs: Default::default(),
|
||||||
|
show_all_fs: Default::default(),
|
||||||
|
show_listed_fs: Default::default(),
|
||||||
|
block_size: Default::default(),
|
||||||
|
fs_selector: Default::default(),
|
||||||
|
show_total: Default::default(),
|
||||||
|
columns: vec![
|
||||||
|
Column::Source,
|
||||||
|
Column::Size,
|
||||||
|
Column::Used,
|
||||||
|
Column::Avail,
|
||||||
|
Column::Pcent,
|
||||||
|
Column::Target,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OptionsError {
|
enum OptionsError {
|
||||||
|
@ -103,12 +124,11 @@ impl Options {
|
||||||
show_local_fs: matches.is_present(OPT_LOCAL),
|
show_local_fs: matches.is_present(OPT_LOCAL),
|
||||||
show_all_fs: matches.is_present(OPT_ALL),
|
show_all_fs: matches.is_present(OPT_ALL),
|
||||||
show_listed_fs: false,
|
show_listed_fs: false,
|
||||||
show_fs_type: matches.is_present(OPT_PRINT_TYPE),
|
|
||||||
show_inode_instead: matches.is_present(OPT_INODES),
|
|
||||||
block_size: block_size_from_matches(matches)
|
block_size: block_size_from_matches(matches)
|
||||||
.map_err(|_| OptionsError::InvalidBlockSize)?,
|
.map_err(|_| OptionsError::InvalidBlockSize)?,
|
||||||
fs_selector: FsSelector::from(matches),
|
fs_selector: FsSelector::from(matches),
|
||||||
show_total: matches.is_present(OPT_TOTAL),
|
show_total: matches.is_present(OPT_TOTAL),
|
||||||
|
columns: Column::from_matches(matches),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// *
|
// *
|
||||||
// * For the full copyright and license information, please view the LICENSE
|
// * For the full copyright and license information, please view the LICENSE
|
||||||
// * file that was distributed with this source code.
|
// * file that was distributed with this source code.
|
||||||
// spell-checker:ignore tmpfs
|
// spell-checker:ignore tmpfs Pcent Itotal Iused Iavail Ipcent
|
||||||
//! The filesystem usage data table.
|
//! The filesystem usage data table.
|
||||||
//!
|
//!
|
||||||
//! A table comprises a header row ([`Header`]) and a collection of
|
//! A table comprises a header row ([`Header`]) and a collection of
|
||||||
|
@ -11,6 +11,7 @@
|
||||||
//! [`DisplayRow`] implements [`std::fmt::Display`].
|
//! [`DisplayRow`] implements [`std::fmt::Display`].
|
||||||
use number_prefix::NumberPrefix;
|
use number_prefix::NumberPrefix;
|
||||||
|
|
||||||
|
use crate::columns::Column;
|
||||||
use crate::{BlockSize, Filesystem, Options};
|
use crate::{BlockSize, Filesystem, Options};
|
||||||
use uucore::fsext::{FsUsage, MountInfo};
|
use uucore::fsext::{FsUsage, MountInfo};
|
||||||
|
|
||||||
|
@ -225,56 +226,37 @@ impl<'a> DisplayRow<'a> {
|
||||||
Some(x) => format!("{:.0}%", (100.0 * x).ceil()),
|
Some(x) => format!("{:.0}%", (100.0 * x).ceil()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write the bytes data for this row.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// If there is a problem writing to `f`.
|
|
||||||
///
|
|
||||||
/// If the scaling factor is not 1000, 1024, or a negative number.
|
|
||||||
fn fmt_bytes(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{0: >12} ", self.scaled(self.row.bytes)?)?;
|
|
||||||
write!(f, "{0: >12} ", self.scaled(self.row.bytes_used)?)?;
|
|
||||||
write!(f, "{0: >12} ", self.scaled(self.row.bytes_free)?)?;
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{0: >12} ",
|
|
||||||
DisplayRow::percentage(self.row.bytes_capacity)
|
|
||||||
)?;
|
|
||||||
write!(f, "{0: >5} ", DisplayRow::percentage(self.row.bytes_usage))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write the inodes data for this row.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// If there is a problem writing to `f`.
|
|
||||||
///
|
|
||||||
/// If the scaling factor is not 1000, 1024, or a negative number.
|
|
||||||
fn fmt_inodes(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{0: >12} ", self.scaled(self.row.inodes)?)?;
|
|
||||||
write!(f, "{0: >12} ", self.scaled(self.row.inodes_used)?)?;
|
|
||||||
write!(f, "{0: >12} ", self.scaled(self.row.inodes_free)?)?;
|
|
||||||
write!(f, "{0: >5} ", DisplayRow::percentage(self.row.inodes_usage))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for DisplayRow<'_> {
|
impl fmt::Display for DisplayRow<'_> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{0: <16} ", self.row.fs_device)?;
|
for column in &self.options.columns {
|
||||||
if self.options.show_fs_type {
|
match column {
|
||||||
write!(f, "{0: <5} ", self.row.fs_type)?;
|
Column::Source => write!(f, "{0: <16} ", self.row.fs_device)?,
|
||||||
|
Column::Size => write!(f, "{0: >12} ", self.scaled(self.row.bytes)?)?,
|
||||||
|
Column::Used => write!(f, "{0: >12} ", self.scaled(self.row.bytes_used)?)?,
|
||||||
|
Column::Avail => write!(f, "{0: >12} ", self.scaled(self.row.bytes_free)?)?,
|
||||||
|
Column::Pcent => {
|
||||||
|
write!(f, "{0: >5} ", DisplayRow::percentage(self.row.bytes_usage))?;
|
||||||
|
}
|
||||||
|
Column::Target => write!(f, "{0: <16}", self.row.fs_mount)?,
|
||||||
|
Column::Itotal => write!(f, "{0: >12} ", self.scaled(self.row.inodes)?)?,
|
||||||
|
Column::Iused => write!(f, "{0: >12} ", self.scaled(self.row.inodes_used)?)?,
|
||||||
|
Column::Iavail => write!(f, "{0: >12} ", self.scaled(self.row.inodes_free)?)?,
|
||||||
|
Column::Ipcent => {
|
||||||
|
write!(f, "{0: >5} ", DisplayRow::percentage(self.row.inodes_usage))?;
|
||||||
|
}
|
||||||
|
// TODO Implement this.
|
||||||
|
Column::File => {}
|
||||||
|
Column::Fstype => write!(f, "{0: <5} ", self.row.fs_type)?,
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
Column::Capacity => write!(
|
||||||
|
f,
|
||||||
|
"{0: >12} ",
|
||||||
|
DisplayRow::percentage(self.row.bytes_capacity)
|
||||||
|
)?,
|
||||||
}
|
}
|
||||||
if self.options.show_inode_instead {
|
|
||||||
self.fmt_inodes(f)?;
|
|
||||||
} else {
|
|
||||||
self.fmt_bytes(f)?;
|
|
||||||
}
|
}
|
||||||
write!(f, "{0: <16}", self.row.fs_mount)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,29 +278,29 @@ impl<'a> Header<'a> {
|
||||||
|
|
||||||
impl fmt::Display for Header<'_> {
|
impl fmt::Display for Header<'_> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{0: <16} ", "Filesystem")?;
|
for column in &self.options.columns {
|
||||||
if self.options.show_fs_type {
|
match column {
|
||||||
write!(f, "{0: <5} ", "Type")?;
|
Column::Source => write!(f, "{0: <16} ", "Filesystem")?,
|
||||||
}
|
// `Display` is implemented for `BlockSize`, but
|
||||||
if self.options.show_inode_instead {
|
// `Display` only works when formatting an object into
|
||||||
write!(f, "{0: >12} ", "Inodes")?;
|
// an empty format, `{}`. So we use `format!()` first
|
||||||
write!(f, "{0: >12} ", "IUsed")?;
|
// to create the string, then use `write!()` to align
|
||||||
write!(f, "{0: >12} ", "IFree")?;
|
// the string and pad with spaces.
|
||||||
write!(f, "{0: >5} ", "IUse%")?;
|
Column::Size => write!(f, "{0: >12} ", format!("{}", self.options.block_size))?,
|
||||||
} else {
|
Column::Used => write!(f, "{0: >12} ", "Used")?,
|
||||||
// `Display` is implemented for `BlockSize`, but `Display`
|
Column::Avail => write!(f, "{0: >12} ", "Available")?,
|
||||||
// only works when formatting an object into an empty
|
Column::Pcent => write!(f, "{0: >5} ", "Use%")?,
|
||||||
// format, `{}`. So we use `format!()` first to create the
|
Column::Target => write!(f, "{0: <16} ", "Mounted on")?,
|
||||||
// string, then use `write!()` to align the string and pad
|
Column::Itotal => write!(f, "{0: >12} ", "Inodes")?,
|
||||||
// with spaces.
|
Column::Iused => write!(f, "{0: >12} ", "IUsed")?,
|
||||||
write!(f, "{0: >12} ", format!("{}", self.options.block_size))?;
|
Column::Iavail => write!(f, "{0: >12} ", "IFree")?,
|
||||||
write!(f, "{0: >12} ", "Used")?;
|
Column::Ipcent => write!(f, "{0: >5} ", "IUse%")?,
|
||||||
write!(f, "{0: >12} ", "Available")?;
|
Column::File => write!(f, "{0: <16}", "File")?,
|
||||||
|
Column::Fstype => write!(f, "{0: <5} ", "Type")?,
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
write!(f, "{0: >12} ", "Capacity")?;
|
Column::Capacity => write!(f, "{0: >12} ", "Capacity")?,
|
||||||
write!(f, "{0: >5} ", "Use%")?;
|
}
|
||||||
}
|
}
|
||||||
write!(f, "{0: <16} ", "Mounted on")?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,9 +308,28 @@ impl fmt::Display for Header<'_> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
|
use crate::columns::Column;
|
||||||
use crate::table::{DisplayRow, Header, Row};
|
use crate::table::{DisplayRow, Header, Row};
|
||||||
use crate::{BlockSize, Options};
|
use crate::{BlockSize, Options};
|
||||||
|
|
||||||
|
const COLUMNS_WITH_FS_TYPE: [Column; 7] = [
|
||||||
|
Column::Source,
|
||||||
|
Column::Fstype,
|
||||||
|
Column::Size,
|
||||||
|
Column::Used,
|
||||||
|
Column::Avail,
|
||||||
|
Column::Pcent,
|
||||||
|
Column::Target,
|
||||||
|
];
|
||||||
|
const COLUMNS_WITH_INODES: [Column; 6] = [
|
||||||
|
Column::Source,
|
||||||
|
Column::Itotal,
|
||||||
|
Column::Iused,
|
||||||
|
Column::Iavail,
|
||||||
|
Column::Ipcent,
|
||||||
|
Column::Target,
|
||||||
|
];
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display() {
|
fn test_header_display() {
|
||||||
let options = Default::default();
|
let options = Default::default();
|
||||||
|
@ -341,7 +342,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display_fs_type() {
|
fn test_header_display_fs_type() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
show_fs_type: true,
|
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -353,7 +354,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display_inode() {
|
fn test_header_display_inode() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
show_inode_instead: true,
|
columns: COLUMNS_WITH_INODES.to_vec(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -431,8 +432,8 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display_fs_type() {
|
fn test_row_display_fs_type() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
|
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||||
block_size: BlockSize::Bytes(1),
|
block_size: BlockSize::Bytes(1),
|
||||||
show_fs_type: true,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let row = Row {
|
let row = Row {
|
||||||
|
@ -462,8 +463,8 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display_inodes() {
|
fn test_row_display_inodes() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
|
columns: COLUMNS_WITH_INODES.to_vec(),
|
||||||
block_size: BlockSize::Bytes(1),
|
block_size: BlockSize::Bytes(1),
|
||||||
show_inode_instead: true,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let row = Row {
|
let row = Row {
|
||||||
|
@ -494,7 +495,7 @@ mod tests {
|
||||||
fn test_row_display_human_readable_si() {
|
fn test_row_display_human_readable_si() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
block_size: BlockSize::HumanReadableDecimal,
|
block_size: BlockSize::HumanReadableDecimal,
|
||||||
show_fs_type: true,
|
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let row = Row {
|
let row = Row {
|
||||||
|
@ -525,7 +526,7 @@ mod tests {
|
||||||
fn test_row_display_human_readable_binary() {
|
fn test_row_display_human_readable_binary() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
block_size: BlockSize::HumanReadableBinary,
|
block_size: BlockSize::HumanReadableBinary,
|
||||||
show_fs_type: true,
|
columns: COLUMNS_WITH_FS_TYPE.to_vec(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let row = Row {
|
let row = Row {
|
||||||
|
|
|
@ -43,21 +43,14 @@ fn test_df_output() {
|
||||||
/// Test that the order of rows in the table does not change across executions.
|
/// Test that the order of rows in the table does not change across executions.
|
||||||
#[test]
|
#[test]
|
||||||
fn test_order_same() {
|
fn test_order_same() {
|
||||||
// TODO When #3057 is resolved, we should just use
|
let output1 = new_ucmd!()
|
||||||
//
|
.arg("--output=source")
|
||||||
// new_ucmd!().arg("--output=source").succeeds().stdout_move_str();
|
.succeeds()
|
||||||
//
|
.stdout_move_str();
|
||||||
// instead of parsing the entire `df` table as a string.
|
let output2 = new_ucmd!()
|
||||||
let output1 = new_ucmd!().succeeds().stdout_move_str();
|
.arg("--output=source")
|
||||||
let output2 = new_ucmd!().succeeds().stdout_move_str();
|
.succeeds()
|
||||||
let output1: Vec<String> = output1
|
.stdout_move_str();
|
||||||
.lines()
|
|
||||||
.map(|l| String::from(l.split_once(' ').unwrap().0))
|
|
||||||
.collect();
|
|
||||||
let output2: Vec<String> = output2
|
|
||||||
.lines()
|
|
||||||
.map(|l| String::from(l.split_once(' ').unwrap().0))
|
|
||||||
.collect();
|
|
||||||
assert_eq!(output1, output2);
|
assert_eq!(output1, output2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,4 +176,33 @@ fn test_block_size_1024() {
|
||||||
assert_eq!(get_header(34 * 1024 * 1024 * 1024), "34G-blocks");
|
assert_eq!(get_header(34 * 1024 * 1024 * 1024), "34G-blocks");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO The spacing does not match GNU df. Also we need to remove
|
||||||
|
// trailing spaces from the heading row.
|
||||||
|
#[test]
|
||||||
|
fn test_output_selects_columns() {
|
||||||
|
let output = new_ucmd!()
|
||||||
|
.args(&["--output=source"])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_move_str();
|
||||||
|
assert_eq!(output.lines().next().unwrap(), "Filesystem ");
|
||||||
|
|
||||||
|
let output = new_ucmd!()
|
||||||
|
.args(&["--output=source,target"])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_move_str();
|
||||||
|
assert_eq!(
|
||||||
|
output.lines().next().unwrap(),
|
||||||
|
"Filesystem Mounted on "
|
||||||
|
);
|
||||||
|
|
||||||
|
let output = new_ucmd!()
|
||||||
|
.args(&["--output=source,target,used"])
|
||||||
|
.succeeds()
|
||||||
|
.stdout_move_str();
|
||||||
|
assert_eq!(
|
||||||
|
output.lines().next().unwrap(),
|
||||||
|
"Filesystem Mounted on Used "
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ToDO: more tests...
|
// ToDO: more tests...
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue