add tests templates

This commit is contained in:
Sylvestre Ledru
2024-01-26 20:06:52 +01:00
parent 23352028a7
commit 59206dfff0
11 changed files with 4081 additions and 0 deletions

129
Cargo.lock generated
View File

@@ -183,6 +183,23 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "fastrand"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
[[package]]
name = "getrandom"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "glob"
version = "0.3.1"
@@ -195,6 +212,12 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "io-lifetimes"
version = "1.0.11"
@@ -206,6 +229,12 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.152"
@@ -303,6 +332,12 @@ dependencies = [
"siphasher",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "pretty_assertions"
version = "1.4.0"
@@ -322,6 +357,29 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "procfs"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4"
dependencies = [
"bitflags 2.4.1",
"hex",
"lazy_static",
"procfs-core",
"rustix 0.38.30",
]
[[package]]
name = "procfs-core"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29"
dependencies = [
"bitflags 2.4.1",
"hex",
]
[[package]]
name = "quote"
version = "1.0.35"
@@ -337,6 +395,18 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
@@ -345,6 +415,9 @@ name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rayon"
@@ -366,6 +439,15 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "regex"
version = "1.10.2"
@@ -395,6 +477,15 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rlimit"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3560f70f30a0f16d11d01ed078a07740fe6b489667abc7c7b029155d9f21c3d8"
dependencies = [
"libc",
]
[[package]]
name = "roff"
version = "0.2.1"
@@ -461,6 +552,19 @@ dependencies = [
"windows",
]
[[package]]
name = "tempfile"
version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
dependencies = [
"cfg-if",
"fastrand",
"redox_syscall",
"rustix 0.38.30",
"windows-sys 0.52.0",
]
[[package]]
name = "terminal_size"
version = "0.2.6"
@@ -524,15 +628,22 @@ dependencies = [
"clap",
"clap_complete",
"clap_mangen",
"libc",
"phf",
"phf_codegen",
"pretty_assertions",
"procfs",
"rand",
"regex",
"rlimit",
"tempfile",
"textwrap",
"uu_lscpu",
"uu_mountpoint",
"uu_pwdx",
"uu_renice",
"uucore",
"xattr",
]
[[package]]
@@ -578,6 +689,7 @@ checksum = "d5de2eba1364f6274f35f121eb8671b98ac5fa8fe1271694721e17034e85e8bc"
dependencies = [
"clap",
"glob",
"libc",
"nix",
"once_cell",
"os_display",
@@ -602,6 +714,12 @@ version = "0.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d841f8408028085ca65896cdd60b9925d4e407cb69989a64889f2bebbb51147b"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wild"
version = "2.2.0"
@@ -784,6 +902,17 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "xattr"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f"
dependencies = [
"libc",
"linux-raw-sys 0.4.12",
"rustix 0.38.30",
]
[[package]]
name = "yansi"
version = "0.5.1"

View File

@@ -42,6 +42,9 @@ libc = "0.2.152"
phf = "0.11.2"
phf_codegen = "0.11.2"
textwrap = { version = "0.16.0", features = ["terminal_size"] }
xattr = "1.3.1"
tempfile = "3.9.0"
rand = { version = "0.8", features = ["small_rng"] }
[dependencies]
clap = { workspace = true }
@@ -60,10 +63,23 @@ mountpoint = { optional = true, version = "0.0.1", package = "uu_mountpoint", pa
[dev-dependencies]
pretty_assertions = "1"
regex = { workspace = true }
tempfile = { workspace = true }
libc = { workspace = true }
rand = { workspace = true }
uucore = { workspace = true, features = ["entries", "process", "signals"] }
[target.'cfg(unix)'.dev-dependencies]
xattr = { workspace = true }
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dev-dependencies]
procfs = { version = "0.16", default-features = false }
rlimit = "0.10.1"
[build-dependencies]
phf_codegen = { workspace = true }
[[bin]]
name = "util-linux"
path = "src/bin/util-linux.rs"

View File

@@ -0,0 +1,15 @@
// This file is part of the uutils util-linux package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (words) symdir somefakedir
use std::path::PathBuf;
use crate::common::util::{TestScenario, UCommand};
#[test]
#[ignore]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}

View File

@@ -0,0 +1,14 @@
// This file is part of the uutils util-linux package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (words) symdir somefakedir
use std::path::PathBuf;
use crate::common::util::{TestScenario, UCommand};
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}

View File

@@ -0,0 +1,14 @@
// This file is part of the uutils util-linux package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (words) symdir somefakedir
use std::path::PathBuf;
use crate::common::util::{TestScenario, UCommand};
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}

View File

@@ -0,0 +1,13 @@
// This file is part of the uutils util-linux package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (words) symdir somefakedir
use crate::common::util::{TestScenario, UCommand};
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}

93
tests/common/macros.rs Normal file
View File

@@ -0,0 +1,93 @@
// 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.
/// Platform-independent helper for constructing a `PathBuf` from individual elements
#[macro_export]
macro_rules! path_concat {
($e:expr, ..$n:expr) => {{
use std::path::PathBuf;
let n = $n;
let mut pb = PathBuf::new();
for _ in 0..n {
pb.push($e);
}
pb.to_str().unwrap().to_owned()
}};
($($e:expr),*) => {{
use std::path::PathBuf;
let mut pb = PathBuf::new();
$(
pb.push($e);
)*
pb.to_str().unwrap().to_owned()
}};
}
/// Deduce the name of the test binary from the test filename.
///
/// e.g.: `tests/by-util/test_cat.rs` -> `cat`
#[macro_export]
macro_rules! util_name {
() => {
module_path!()
.split("_")
.nth(1)
.and_then(|s| s.split("::").next())
.expect("no test name")
};
}
/// Convenience macro for acquiring a [`UCommand`] builder.
///
/// Returns the following:
/// - a [`UCommand`] builder for invoking the binary to be tested
///
/// This macro is intended for quick, single-call tests. For more complex tests
/// that require multiple invocations of the tested binary, see [`TestScenario`]
///
/// [`UCommand`]: crate::tests::common::util::UCommand
/// [`TestScenario]: crate::tests::common::util::TestScenario
#[macro_export]
macro_rules! new_ucmd {
() => {
TestScenario::new(util_name!()).ucmd()
};
}
/// Convenience macro for acquiring a [`UCommand`] builder and a test path.
///
/// Returns a tuple containing the following:
/// - an [`AtPath`] that points to a unique temporary test directory
/// - a [`UCommand`] builder for invoking the binary to be tested
///
/// This macro is intended for quick, single-call tests. For more complex tests
/// that require multiple invocations of the tested binary, see [`TestScenario`]
///
/// [`UCommand`]: crate::tests::common::util::UCommand
/// [`AtPath`]: crate::tests::common::util::AtPath
/// [`TestScenario]: crate::tests::common::util::TestScenario
#[macro_export]
macro_rules! at_and_ucmd {
() => {{
let ts = TestScenario::new(util_name!());
(ts.fixtures.clone(), ts.ucmd())
}};
}
/// If `common::util::expected_result` returns an error, i.e. the `util` in `$PATH` doesn't
/// include a coreutils version string or the version is too low,
/// this macro can be used to automatically skip the test and print the reason.
#[macro_export]
macro_rules! unwrap_or_return {
( $e:expr ) => {
match $e {
Ok(x) => x,
Err(e) => {
println!("test skipped: {}", e);
return;
}
}
};
}

8
tests/common/mod.rs Normal file
View File

@@ -0,0 +1,8 @@
// 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.
#[macro_use]
pub mod macros;
pub mod random;
pub mod util;

339
tests/common/random.rs Normal file
View File

@@ -0,0 +1,339 @@
// 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.
use rand::distributions::{Distribution, Uniform};
use rand::{thread_rng, Rng};
/// Samples alphanumeric characters `[A-Za-z0-9]` including newline `\n`
///
/// # Examples
///
/// ```rust,ignore
/// use rand::{Rng, thread_rng};
///
/// let vec = thread_rng()
/// .sample_iter(AlphanumericNewline)
/// .take(10)
/// .collect::<Vec<u8>>();
/// println!("Random chars: {}", String::from_utf8(vec).unwrap());
/// ```
#[derive(Clone, Copy, Debug)]
pub struct AlphanumericNewline;
impl AlphanumericNewline {
/// The charset to act upon
const CHARSET: &'static [u8] =
b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n";
/// Generate a random byte from [`Self::CHARSET`] and return it as `u8`.
///
/// # Arguments
///
/// * `rng`: A [`rand::Rng`]
///
/// returns: u8
fn random<R>(rng: &mut R) -> u8
where
R: Rng + ?Sized,
{
let idx = rng.gen_range(0..Self::CHARSET.len());
Self::CHARSET[idx]
}
}
impl Distribution<u8> for AlphanumericNewline {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
Self::random(rng)
}
}
/// Generate a random string from a [`Distribution`]
///
/// # Examples
///
/// ```rust,ignore
/// use crate::common::random::{AlphanumericNewline, RandomString};
/// use rand::distributions::Alphanumeric;
///
/// // generates a 100 byte string with characters from AlphanumericNewline
/// let random_string = RandomString::generate(AlphanumericNewline, 100);
/// assert_eq!(100, random_string.len());
///
/// // generates a 100 byte string with 10 newline characters not ending with a newline
/// let string = RandomString::generate_with_delimiter(Alphanumeric, b'\n', 10, false, 100);
/// assert_eq!(100, random_string.len());
/// ```
pub struct RandomString;
impl RandomString {
/// Generate a random string from the given [`Distribution`] with the given `length` in bytes.
///
/// # Arguments
///
/// * `dist`: A u8 [`Distribution`]
/// * `length`: the length of the resulting string in bytes
///
/// returns: String
pub fn generate<D>(dist: D, length: usize) -> String
where
D: Distribution<u8>,
{
thread_rng()
.sample_iter(dist)
.take(length)
.map(|b| b as char)
.collect()
}
/// Generate a random string from the [`Distribution`] with the given `length` in bytes. The
/// function takes a `delimiter`, which is randomly distributed in the string, such that exactly
/// `num_delimiter` amount of `delimiter`s occur. If `end_with_delimiter` is set, then the
/// string ends with the delimiter, else the string does not end with the delimiter.
///
/// # Arguments
///
/// * `dist`: A `u8` [`Distribution`]
/// * `delimiter`: A `u8` delimiter, which does not need to be included in the `Distribution`
/// * `num_delimiter`: The number of `delimiter`s contained in the resulting string
/// * `end_with_delimiter`: If the string shall end with the given delimiter
/// * `length`: the length of the resulting string in bytes
///
/// returns: String
///
/// # Examples
///
/// ```rust,ignore
/// use crate::common::random::{AlphanumericNewline, RandomString};
///
/// // generates a 100 byte string with 10 '\0' byte characters not ending with a '\0' byte
/// let string = RandomString::generate_with_delimiter(AlphanumericNewline, 0, 10, false, 100);
/// assert_eq!(100, random_string.len());
/// assert_eq!(
/// 10,
/// random_string.as_bytes().iter().filter(|p| **p == 0).count()
/// );
/// assert!(!random_string.as_bytes().ends_with(&[0]));
/// ```
pub fn generate_with_delimiter<D>(
dist: D,
delimiter: u8,
num_delimiter: usize,
end_with_delimiter: bool,
length: usize,
) -> String
where
D: Distribution<u8>,
{
if length == 0 {
return String::new();
} else if length == 1 {
return if num_delimiter > 0 {
String::from(delimiter as char)
} else {
String::from(thread_rng().sample(&dist) as char)
};
}
let samples = length - 1;
let mut result: Vec<u8> = thread_rng().sample_iter(&dist).take(samples).collect();
if num_delimiter == 0 {
result.push(thread_rng().sample(&dist));
return String::from_utf8(result).unwrap();
}
let num_delimiter = if end_with_delimiter {
num_delimiter - 1
} else {
num_delimiter
};
let between = Uniform::new(0, samples);
for _ in 0..num_delimiter {
let mut pos = between.sample(&mut thread_rng());
let turn = pos;
while result[pos] == delimiter {
pos += 1;
if pos >= samples {
pos = 0;
}
if pos == turn {
break;
}
}
result[pos] = delimiter;
}
if end_with_delimiter {
result.push(delimiter);
} else {
result.push(thread_rng().sample(&dist));
}
String::from_utf8(result).unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::distributions::Alphanumeric;
#[test]
fn test_random_string_generate() {
let random_string = RandomString::generate(AlphanumericNewline, 0);
assert_eq!(0, random_string.len());
let random_string = RandomString::generate(AlphanumericNewline, 1);
assert_eq!(1, random_string.len());
let random_string = RandomString::generate(AlphanumericNewline, 100);
assert_eq!(100, random_string.len());
}
#[test]
fn test_random_string_generate_with_delimiter_when_length_is_zero() {
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 0, false, 0);
assert_eq!(0, random_string.len());
}
#[test]
fn test_random_string_generate_with_delimiter_when_num_delimiter_is_greater_than_length() {
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 2, false, 1);
assert_eq!(1, random_string.len());
assert!(random_string.as_bytes().contains(&0));
assert!(random_string.as_bytes().ends_with(&[0]));
}
#[test]
fn test_random_string_generate_with_delimiter_should_end_with_delimiter() {
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, true, 1);
assert_eq!(1, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, false, 1);
assert_eq!(1, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, true, 2);
assert_eq!(2, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 2, true, 2);
assert_eq!(2, random_string.len());
assert_eq!(
2,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, true, 3);
assert_eq!(3, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
}
#[test]
fn test_random_string_generate_with_delimiter_should_not_end_with_delimiter() {
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 0, false, 1);
assert_eq!(1, random_string.len());
assert_eq!(
0,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 0, true, 1);
assert_eq!(1, random_string.len());
assert_eq!(
0,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, false, 2);
assert_eq!(2, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(!random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 1, false, 3);
assert_eq!(3, random_string.len());
assert_eq!(
1,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(!random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 2, false, 3);
assert_eq!(3, random_string.len());
assert_eq!(
2,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(!random_string.as_bytes().ends_with(&[0]));
}
#[test]
fn test_generate_with_delimiter_with_greater_length() {
let random_string =
RandomString::generate_with_delimiter(Alphanumeric, 0, 100, false, 1000);
assert_eq!(1000, random_string.len());
assert_eq!(
100,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(!random_string.as_bytes().ends_with(&[0]));
let random_string = RandomString::generate_with_delimiter(Alphanumeric, 0, 100, true, 1000);
assert_eq!(1000, random_string.len());
assert_eq!(
100,
random_string.as_bytes().iter().filter(|p| **p == 0).count()
);
assert!(random_string.as_bytes().ends_with(&[0]));
}
/// Originally used to exclude an error within the `random` module. The two
/// affected tests timed out on windows, but only in the ci. These tests are
/// also the source for the concrete numbers. The timed out tests are
/// `test_tail.rs::test_pipe_when_lines_option_given_input_size_has_multiple_size_of_buffer_size`
/// `test_tail.rs::test_pipe_when_bytes_option_given_input_size_has_multiple_size_of_buffer_size`.
#[test]
fn test_generate_random_strings_when_length_is_around_critical_buffer_sizes() {
let length = 8192 * 3;
let random_string = RandomString::generate(AlphanumericNewline, length);
assert_eq!(length, random_string.len());
let length = 8192 * 3 + 1;
let random_string =
RandomString::generate_with_delimiter(Alphanumeric, b'\n', 100, true, length);
assert_eq!(length, random_string.len());
assert_eq!(
100,
random_string
.as_bytes()
.iter()
.filter(|p| **p == b'\n')
.count()
);
assert!(!random_string.as_bytes().ends_with(&[0]));
}
}

3418
tests/common/util.rs Normal file

File diff suppressed because it is too large Load Diff

22
tests/tests.rs Normal file
View File

@@ -0,0 +1,22 @@
// 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.
#[macro_use]
mod common;
#[cfg(feature = "lscpu")]
#[path = "by-util/test_lscpu.rs"]
mod test_lscpu;
#[cfg(feature = "pwdx")]
#[path = "by-util/test_pwdx.rs"]
mod test_pwdx;
#[cfg(feature = "mountpoint")]
#[path = "by-util/test_mountpoint.rs"]
mod test_mountpoint;
#[cfg(feature = "renice")]
#[path = "by-util/test_renice.rs"]
mod test_renice;