mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
uniq: pass remaining GNU tests (#5994)
This commit is contained in:
+372
-118
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@ pub use crate::mods::error;
|
||||
pub use crate::mods::line_ending;
|
||||
pub use crate::mods::os;
|
||||
pub use crate::mods::panic;
|
||||
pub use crate::mods::posix;
|
||||
|
||||
// * string parsing modules
|
||||
pub use crate::parser::parse_glob;
|
||||
|
||||
@@ -9,3 +9,4 @@ pub mod error;
|
||||
pub mod line_ending;
|
||||
pub mod os;
|
||||
pub mod panic;
|
||||
pub mod posix;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// 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 (vars)
|
||||
//! Iterate over lines, including the line ending character(s).
|
||||
//!
|
||||
//! This module provides the [`posix_version`] function, that returns
|
||||
//! Some(usize) if the `_POSIX2_VERSION` environment variable is defined
|
||||
//! and has value that can be parsed.
|
||||
//! Otherwise returns None, so the calling utility would assume default behavior.
|
||||
//!
|
||||
//! NOTE: GNU (as of v9.4) recognizes three distinct values for POSIX version:
|
||||
//! '199209' for POSIX 1003.2-1992, which would define Obsolete mode
|
||||
//! '200112' for POSIX 1003.1-2001, which is the minimum version for Traditional mode
|
||||
//! '200809' for POSIX 1003.1-2008, which is the minimum version for Modern mode
|
||||
//!
|
||||
//! Utilities that rely on this module:
|
||||
//! `sort` (TBD)
|
||||
//! `tail` (TBD)
|
||||
//! `touch` (TBD)
|
||||
//! `uniq`
|
||||
//!
|
||||
use std::env;
|
||||
|
||||
pub const OBSOLETE: usize = 199209;
|
||||
pub const TRADITIONAL: usize = 200112;
|
||||
pub const MODERN: usize = 200809;
|
||||
|
||||
pub fn posix_version() -> Option<usize> {
|
||||
env::var("_POSIX2_VERSION")
|
||||
.ok()
|
||||
.and_then(|v| v.parse::<usize>().ok())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::posix::*;
|
||||
|
||||
#[test]
|
||||
fn test_posix_version() {
|
||||
// default
|
||||
assert_eq!(posix_version(), None);
|
||||
// set specific version
|
||||
env::set_var("_POSIX2_VERSION", OBSOLETE.to_string());
|
||||
assert_eq!(posix_version(), Some(OBSOLETE));
|
||||
env::set_var("_POSIX2_VERSION", TRADITIONAL.to_string());
|
||||
assert_eq!(posix_version(), Some(TRADITIONAL));
|
||||
env::set_var("_POSIX2_VERSION", MODERN.to_string());
|
||||
assert_eq!(posix_version(), Some(MODERN));
|
||||
}
|
||||
}
|
||||
+122
-40
@@ -2,10 +2,10 @@
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
use std::io::Write;
|
||||
|
||||
// spell-checker:ignore nabcd
|
||||
// spell-checker:ignore nabcd badoption schar
|
||||
use crate::common::util::TestScenario;
|
||||
use uucore::posix::OBSOLETE;
|
||||
|
||||
static INPUT: &str = "sorted.txt";
|
||||
static OUTPUT: &str = "sorted-output.txt";
|
||||
@@ -118,10 +118,10 @@ fn test_stdin_skip_21_fields_obsolete() {
|
||||
#[test]
|
||||
fn test_stdin_skip_invalid_fields_obsolete() {
|
||||
new_ucmd!()
|
||||
.args(&["-5deadbeef"])
|
||||
.args(&["-5q"])
|
||||
.run()
|
||||
.failure()
|
||||
.stderr_only("uniq: Invalid argument for skip-fields: 5deadbeef\n");
|
||||
.stderr_contains("error: unexpected argument '-q' found\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -138,8 +138,7 @@ fn test_all_repeated_followed_by_filename() {
|
||||
let filename = "test.txt";
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
let mut file = at.make_file(filename);
|
||||
file.write_all(b"a\na\n").unwrap();
|
||||
at.write(filename, "a\na\n");
|
||||
|
||||
ucmd.args(&["--all-repeated", filename])
|
||||
.run()
|
||||
@@ -202,14 +201,13 @@ fn test_stdin_zero_terminated() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_utf8() {
|
||||
fn test_gnu_locale_fr_schar() {
|
||||
new_ucmd!()
|
||||
.arg("not-utf8-sequence.txt")
|
||||
.args(&["-f1", "locale-fr-schar.txt"])
|
||||
.env("LC_ALL", "C")
|
||||
.run()
|
||||
.failure()
|
||||
.stderr_only(
|
||||
"uniq: failed to convert line to utf8: invalid utf-8 sequence of 1 bytes from index 0\n",
|
||||
);
|
||||
.success()
|
||||
.stdout_is_fixture_bytes("locale-fr-schar.txt");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -226,8 +224,7 @@ fn test_group_followed_by_filename() {
|
||||
let filename = "test.txt";
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
|
||||
let mut file = at.make_file(filename);
|
||||
file.write_all(b"a\na\n").unwrap();
|
||||
at.write(filename, "a\na\n");
|
||||
|
||||
ucmd.args(&["--group", filename])
|
||||
.run()
|
||||
@@ -521,23 +518,23 @@ fn gnu_tests() {
|
||||
stderr: None,
|
||||
exit: None,
|
||||
},
|
||||
// // Obsolete syntax for "-s 1"
|
||||
// TestCase {
|
||||
// name: "obs-plus40",
|
||||
// args: &["+1"],
|
||||
// input: "aaa\naaa\n",
|
||||
// stdout: Some("aaa\n"),
|
||||
// stderr: None,
|
||||
// exit: None,
|
||||
// },
|
||||
// TestCase {
|
||||
// name: "obs-plus41",
|
||||
// args: &["+1"],
|
||||
// input: "baa\naaa\n",
|
||||
// stdout: Some("baa\n"),
|
||||
// stderr: None,
|
||||
// exit: None,
|
||||
// },
|
||||
// Obsolete syntax for "-s 1"
|
||||
TestCase {
|
||||
name: "obs-plus40",
|
||||
args: &["+1"],
|
||||
input: "aaa\naaa\n",
|
||||
stdout: Some("aaa\n"),
|
||||
stderr: None,
|
||||
exit: None,
|
||||
},
|
||||
TestCase {
|
||||
name: "obs-plus41",
|
||||
args: &["+1"],
|
||||
input: "baa\naaa\n",
|
||||
stdout: Some("baa\n"),
|
||||
stderr: None,
|
||||
exit: None,
|
||||
},
|
||||
TestCase {
|
||||
name: "42",
|
||||
args: &["-s", "1"],
|
||||
@@ -554,7 +551,6 @@ fn gnu_tests() {
|
||||
stderr: None,
|
||||
exit: None,
|
||||
},
|
||||
/*
|
||||
// Obsolete syntax for "-s 1"
|
||||
TestCase {
|
||||
name: "obs-plus44",
|
||||
@@ -572,7 +568,6 @@ fn gnu_tests() {
|
||||
stderr: None,
|
||||
exit: None,
|
||||
},
|
||||
*/
|
||||
TestCase {
|
||||
name: "50",
|
||||
args: &["-f", "1", "-s", "1"],
|
||||
@@ -757,17 +752,14 @@ fn gnu_tests() {
|
||||
stderr: None,
|
||||
exit: None,
|
||||
},
|
||||
/*
|
||||
Disable as it fails too often. See:
|
||||
https://github.com/uutils/coreutils/issues/3509
|
||||
TestCase {
|
||||
name: "112",
|
||||
args: &["-D", "-c"],
|
||||
input: "a a\na b\n",
|
||||
stdout: Some(""),
|
||||
stderr: Some("uniq: printing all duplicated lines and repeat counts is meaningless"),
|
||||
stderr: Some("uniq: printing all duplicated lines and repeat counts is meaningless\nTry 'uniq --help' for more information.\n"),
|
||||
exit: Some(1),
|
||||
},*/
|
||||
},
|
||||
TestCase {
|
||||
name: "113",
|
||||
args: &["--all-repeated=separate"],
|
||||
@@ -816,6 +808,14 @@ fn gnu_tests() {
|
||||
stderr: None,
|
||||
exit: None,
|
||||
},
|
||||
TestCase {
|
||||
name: "119",
|
||||
args: &["--all-repeated=badoption"],
|
||||
input: "a a\na b\n",
|
||||
stdout: Some(""),
|
||||
stderr: Some("uniq: invalid argument 'badoption' for '--all-repeated'\nValid arguments are:\n - 'none'\n - 'prepend'\n - 'separate'\nTry 'uniq --help' for more information.\n"),
|
||||
exit: Some(1),
|
||||
},
|
||||
// \x08 is the backspace char
|
||||
TestCase {
|
||||
name: "120",
|
||||
@@ -825,6 +825,16 @@ fn gnu_tests() {
|
||||
stderr: None,
|
||||
exit: None,
|
||||
},
|
||||
// u128::MAX = 340282366920938463463374607431768211455
|
||||
TestCase {
|
||||
name: "121",
|
||||
args: &["-d", "-u", "-w340282366920938463463374607431768211456"],
|
||||
input: "a\na\n\x08",
|
||||
stdout: Some(""),
|
||||
stderr: None,
|
||||
exit: None,
|
||||
},
|
||||
// Test 122 is the same as 121, just different big int overflow number
|
||||
TestCase {
|
||||
name: "123",
|
||||
args: &["--zero-terminated"],
|
||||
@@ -969,16 +979,88 @@ fn gnu_tests() {
|
||||
stderr: None,
|
||||
exit: None,
|
||||
},
|
||||
TestCase {
|
||||
name: "141",
|
||||
args: &["--group", "-c"],
|
||||
input: "",
|
||||
stdout: Some(""),
|
||||
stderr: Some("uniq: --group is mutually exclusive with -c/-d/-D/-u\nTry 'uniq --help' for more information.\n"),
|
||||
exit: Some(1),
|
||||
},
|
||||
TestCase {
|
||||
name: "142",
|
||||
args: &["--group", "-d"],
|
||||
input: "",
|
||||
stdout: Some(""),
|
||||
stderr: Some("uniq: --group is mutually exclusive with -c/-d/-D/-u\nTry 'uniq --help' for more information.\n"),
|
||||
exit: Some(1),
|
||||
},
|
||||
TestCase {
|
||||
name: "143",
|
||||
args: &["--group", "-u"],
|
||||
input: "",
|
||||
stdout: Some(""),
|
||||
stderr: Some("uniq: --group is mutually exclusive with -c/-d/-D/-u\nTry 'uniq --help' for more information.\n"),
|
||||
exit: Some(1),
|
||||
},
|
||||
TestCase {
|
||||
name: "144",
|
||||
args: &["--group", "-D"],
|
||||
input: "",
|
||||
stdout: Some(""),
|
||||
stderr: Some("uniq: --group is mutually exclusive with -c/-d/-D/-u\nTry 'uniq --help' for more information.\n"),
|
||||
exit: Some(1),
|
||||
},
|
||||
TestCase {
|
||||
name: "145",
|
||||
args: &["--group=badoption"],
|
||||
input: "",
|
||||
stdout: Some(""),
|
||||
stderr: Some("uniq: invalid argument 'badoption' for '--group'\nValid arguments are:\n - 'prepend'\n - 'append'\n - 'separate'\n - 'both'\nTry 'uniq --help' for more information.\n"),
|
||||
exit: Some(1),
|
||||
},
|
||||
];
|
||||
|
||||
// run regular version of tests with regular file as input
|
||||
for case in cases {
|
||||
// prep input file
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.write("input-file", case.input);
|
||||
|
||||
// first - run a version of tests with regular file as input
|
||||
eprintln!("Test {}", case.name);
|
||||
let result = new_ucmd!().args(case.args).run_piped_stdin(case.input);
|
||||
// set environment variable for obsolete skip char option tests
|
||||
if case.name.starts_with("obs-plus") {
|
||||
ucmd.env("_POSIX2_VERSION", OBSOLETE.to_string());
|
||||
}
|
||||
let result = ucmd.args(case.args).arg("input-file").run();
|
||||
if let Some(stdout) = case.stdout {
|
||||
result.stdout_is(stdout);
|
||||
}
|
||||
if let Some(stderr) = case.stderr {
|
||||
result.stderr_contains(stderr);
|
||||
result.stderr_is(stderr);
|
||||
}
|
||||
if let Some(exit) = case.exit {
|
||||
result.code_is(exit);
|
||||
}
|
||||
|
||||
// then - ".stdin" version of tests with input piped in
|
||||
// NOTE: GNU has another variant for stdin redirect from a file
|
||||
// as in `uniq < input-file`
|
||||
// For now we treat it as equivalent of piped in stdin variant
|
||||
// as in `cat input-file | uniq`
|
||||
eprintln!("Test {}.stdin", case.name);
|
||||
// set environment variable for obsolete skip char option tests
|
||||
let mut ucmd = new_ucmd!();
|
||||
if case.name.starts_with("obs-plus") {
|
||||
ucmd.env("_POSIX2_VERSION", OBSOLETE.to_string());
|
||||
}
|
||||
let result = ucmd.args(case.args).run_piped_stdin(case.input);
|
||||
if let Some(stdout) = case.stdout {
|
||||
result.stdout_is(stdout);
|
||||
}
|
||||
if let Some(stderr) = case.stderr {
|
||||
result.stderr_is(stderr);
|
||||
}
|
||||
if let Some(exit) = case.exit {
|
||||
result.code_is(exit);
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
y z
|
||||
y z
|
||||
Reference in New Issue
Block a user