#![allow(clippy::unwrap_used, clippy::expect_used)]
#![cfg(feature = "localfs")]
mod common;
use common::{kernel_at, run};
use tempfile::tempdir;
fn write_file(dir: &std::path::Path, name: &str, contents: &str) {
std::fs::write(dir.join(name), contents).expect("write fixture");
}
#[tokio::test]
async fn sort_k2_sorts_by_field2_to_eol() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "z bravo\na alpha\nm charlie\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "sort -k 2 data.txt").await;
assert_eq!(code, 0, "sort -k2 should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines, vec!["a alpha", "z bravo", "m charlie"],
"sort -k2 should sort by field 2 to EOL: {out:?}");
}
#[tokio::test]
async fn sort_k2_glued_form() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "z bravo\na alpha\nm charlie\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "sort -k2 data.txt").await;
assert_eq!(code, 0, "sort -k2 glued should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines, vec!["a alpha", "z bravo", "m charlie"],
"glued -k2 should sort by field 2 to EOL: {out:?}");
}
#[tokio::test]
async fn sort_k2_comma_2_sorts_by_field2_only() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "b 10 x\na 20 y\nc 10 z\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, r#"sort -k "2,2" data.txt"#).await;
assert_eq!(code, 0, "sort -k \"2,2\" should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines[2], "a 20 y", "a 20 y has highest field-2 key: {out:?}");
assert!(
lines[0] == "b 10 x" || lines[0] == "c 10 z",
"first two lines are the '10' rows: {out:?}"
);
}
#[tokio::test]
async fn sort_k2_comma_2_unquoted_sorts_by_field2_only() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "b 10 x\na 20 y\nc 10 z\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "sort -k 2,2 data.txt").await;
assert_eq!(code, 0, "sort -k 2,2 should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines[2], "a 20 y", "a 20 y has highest field-2 key: {out:?}");
assert!(
lines[0] == "b 10 x" || lines[0] == "c 10 z",
"first two lines are the '10' rows: {out:?}"
);
}
#[tokio::test]
async fn sort_k2n_glued_numeric() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "alice 10\nbob 9\ncarol 2\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "sort -k2n data.txt").await;
assert_eq!(code, 0, "sort -k2n should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines, vec!["carol 2", "bob 9", "alice 10"],
"sort -k2n should sort field 2 numerically: {out:?}");
}
#[tokio::test]
async fn sort_k2n_separated_numeric() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "alice 10\nbob 9\ncarol 2\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "sort -k 2n data.txt").await;
assert_eq!(code, 0, "sort -k 2n should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines, vec!["carol 2", "bob 9", "alice 10"],
"sort -k 2n separated form should sort field 2 numerically: {out:?}");
}
#[tokio::test]
async fn sort_k2_comma_2n_numeric_stop() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "alice 10\nbob 9\ncarol 2\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, r#"sort -k "2,2n" data.txt"#).await;
assert_eq!(code, 0, "sort -k \"2,2n\" should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines, vec!["carol 2", "bob 9", "alice 10"],
"sort -k2,2n numeric on stop spec: {out:?}");
}
#[tokio::test]
async fn sort_k2_comma_2n_unquoted_numeric_stop() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "alice 10\nbob 9\ncarol 2\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "sort -k 2,2n data.txt").await;
assert_eq!(code, 0, "sort -k 2,2n should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines, vec!["carol 2", "bob 9", "alice 10"],
"sort -k2,2n numeric on stop spec: {out:?}");
}
#[tokio::test]
async fn sort_u_key_dedups_by_key_not_full_line() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "alice 10\nbob 10\ncarol 20\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, r#"sort -k "2,2" -u data.txt"#).await;
assert_eq!(code, 0, "sort -k \"2,2\" -u should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines.len(), 2,
"sort -k2,2 -u should dedup by key field, keeping 2 unique-key lines: {out:?}");
assert_eq!(lines[0], "alice 10", "first '10' key wins: {out:?}");
assert_eq!(lines[1], "carol 20", "carol 20 is the only '20': {out:?}");
}
#[tokio::test]
async fn sort_u_no_key_dedups_full_line() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "apple\nbanana\napple\norange\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "sort -u data.txt").await;
assert_eq!(code, 0, "sort -u should succeed: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines.len(), 3, "sort -u deduplicates full lines: {out:?}");
assert!(lines.contains(&"apple"), "apple present once: {out:?}");
}
#[tokio::test]
async fn sort_plain_alpha_regression() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "banana\napple\ncherry\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "sort data.txt").await;
assert_eq!(code, 0);
assert_eq!(out.trim(), "apple\nbanana\ncherry");
}
#[tokio::test]
async fn sort_numeric_regression() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "10\n2\n1\n20\n3\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "sort -n data.txt").await;
assert_eq!(code, 0);
assert_eq!(out.trim(), "1\n2\n3\n10\n20");
}
#[tokio::test]
async fn sort_reverse_regression() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "banana\napple\ncherry\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "sort -r data.txt").await;
assert_eq!(code, 0);
assert_eq!(out.trim(), "cherry\nbanana\napple");
}
#[tokio::test]
async fn sort_version_regression() {
let dir = tempdir().unwrap();
write_file(dir.path(), "data.txt", "v1.10\nv1.2\nv1.9\n");
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, "sort -V data.txt").await;
assert_eq!(code, 0);
assert_eq!(out.trim(), "v1.2\nv1.9\nv1.10");
}
#[tokio::test]
async fn sort_k2n_via_pipe() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, r#"echo "alice 10
bob 9
carol 2" | sort -k2n"#).await;
assert_eq!(code, 0, "sort -k2n via pipe: {out:?}");
let lines: Vec<&str> = out.lines().collect();
assert_eq!(lines, vec!["carol 2", "bob 9", "alice 10"],
"piped sort -k2n: {out:?}");
}
#[tokio::test]
async fn sort_n_u_dedups_numerically_equal() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, r#"echo "10
10.0
2" | sort -n -u"#).await;
assert_eq!(code, 0, "{out:?}");
assert_eq!(out.lines().collect::<Vec<_>>(), vec!["2", "10"],
"10 and 10.0 are numerically equal — keep one: {out:?}");
}
#[tokio::test]
async fn sort_n_u_keydedups_numerically_equal() {
let dir = tempdir().unwrap();
let kernel = kernel_at(dir.path());
let (out, code) = run(&kernel, r#"echo "a 10
a 10.0
b 2" | sort -n -u -k2"#).await;
assert_eq!(code, 0, "{out:?}");
assert_eq!(out.lines().collect::<Vec<_>>(), vec!["b 2", "a 10"],
"field-2 numerically equal — keep first: {out:?}");
}