mirror of
https://github.com/uutils/coreutils.git
synced 2025-12-23 08:47:37 +00:00
Merge cf0d4d6d39 into 836e5d19c4
This commit is contained in:
commit
97781ba1f6
5 changed files with 210 additions and 17 deletions
|
|
@ -84,6 +84,8 @@ fn gen_manpage<T: Args>(
|
|||
} else {
|
||||
validation::setup_localization_or_exit(utility);
|
||||
let mut cmd = util_map.get(utility).unwrap().1();
|
||||
cmd.set_bin_name(utility.clone());
|
||||
let mut cmd = cmd.display_name(utility);
|
||||
if let Some(zip) = tldr {
|
||||
if let Ok(examples) = write_zip_examples(zip, utility, false) {
|
||||
cmd = cmd.after_help(examples);
|
||||
|
|
@ -292,13 +294,21 @@ fn main() -> io::Result<()> {
|
|||
}
|
||||
|
||||
println!("Writing to utils");
|
||||
let hashsum_cmd = utils.iter().find(|n| *n.0 == "hashsum").unwrap().1.1;
|
||||
for (&name, (_, command)) in utils {
|
||||
if name == "[" {
|
||||
continue;
|
||||
}
|
||||
let p = format!("docs/src/utils/{name}.md");
|
||||
let (utils_name, usage_name, command) = match name {
|
||||
"[" => {
|
||||
continue;
|
||||
}
|
||||
name if is_hashsum_family(name) => {
|
||||
// These use the hashsum
|
||||
("hashsum", name, &hashsum_cmd)
|
||||
}
|
||||
n => (n, n, command),
|
||||
};
|
||||
let p = format!("docs/src/utils/{usage_name}.md");
|
||||
|
||||
let fluent = File::open(format!("src/uu/{name}/locales/en-US.ftl"))
|
||||
let fluent = File::open(format!("src/uu/{utils_name}/locales/en-US.ftl"))
|
||||
.and_then(|mut f: File| {
|
||||
let mut s = String::new();
|
||||
f.read_to_string(&mut s)?;
|
||||
|
|
@ -310,21 +320,68 @@ fn main() -> io::Result<()> {
|
|||
MDWriter {
|
||||
w: Box::new(f),
|
||||
command: command(),
|
||||
name,
|
||||
name: usage_name,
|
||||
tldr_zip: &mut tldr_zip,
|
||||
utils_per_platform: &utils_per_platform,
|
||||
fluent,
|
||||
fluent_key: utils_name.to_string(),
|
||||
}
|
||||
.markdown()?;
|
||||
println!("Wrote to '{p}'");
|
||||
} else {
|
||||
println!("Error writing to {p}");
|
||||
}
|
||||
writeln!(summary, "* [{name}](utils/{name}.md)")?;
|
||||
writeln!(summary, "* [{usage_name}](utils/{usage_name}.md)")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fix_usage(name: &str, usage: String) -> String {
|
||||
match name {
|
||||
"test" => {
|
||||
// replace to [ but not the first two line
|
||||
usage
|
||||
.lines()
|
||||
.enumerate()
|
||||
.map(|(i, l)| {
|
||||
if i > 1 {
|
||||
l.replace("test", "[")
|
||||
} else {
|
||||
l.to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
"hashsum" => usage,
|
||||
name if is_hashsum_family(name) => {
|
||||
usage.replace("--<digest> ", "").replace("hashsum", name)
|
||||
}
|
||||
_ => usage,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_hashsum_family(name: &str) -> bool {
|
||||
matches!(
|
||||
name,
|
||||
"md5sum"
|
||||
| "sha1sum"
|
||||
| "sha224sum"
|
||||
| "sha256sum"
|
||||
| "sha384sum"
|
||||
| "sha512sum"
|
||||
| "sha3sum"
|
||||
| "sha3-224sum"
|
||||
| "sha3-256sum"
|
||||
| "sha3-384sum"
|
||||
| "sha3-512sum"
|
||||
| "shake128sum"
|
||||
| "shake256sum"
|
||||
| "b2sum"
|
||||
| "b3sum"
|
||||
)
|
||||
}
|
||||
|
||||
struct MDWriter<'a, 'b> {
|
||||
w: Box<dyn Write>,
|
||||
command: Command,
|
||||
|
|
@ -332,6 +389,7 @@ struct MDWriter<'a, 'b> {
|
|||
tldr_zip: &'b mut Option<ZipArchive<File>>,
|
||||
utils_per_platform: &'b HashMap<&'b str, Vec<String>>,
|
||||
fluent: Option<String>,
|
||||
fluent_key: String,
|
||||
}
|
||||
|
||||
impl MDWriter<'_, '_> {
|
||||
|
|
@ -351,7 +409,6 @@ impl MDWriter<'_, '_> {
|
|||
fn extract_fluent_value(&self, key: &str) -> Option<String> {
|
||||
let content = self.fluent.as_ref()?;
|
||||
let resource = parser::parse(content.clone()).ok()?;
|
||||
|
||||
for entry in resource.body {
|
||||
if let Entry::Message(Message {
|
||||
id,
|
||||
|
|
@ -362,9 +419,20 @@ impl MDWriter<'_, '_> {
|
|||
if id.name == key {
|
||||
// Simple text extraction - just concatenate text elements
|
||||
let mut result = String::new();
|
||||
use fluent_syntax::ast::{
|
||||
Expression, InlineExpression,
|
||||
PatternElement::{Placeable, TextElement},
|
||||
};
|
||||
for element in elements {
|
||||
if let fluent_syntax::ast::PatternElement::TextElement { value } = element {
|
||||
result.push_str(&value);
|
||||
if let TextElement { ref value } = element {
|
||||
result.push_str(value);
|
||||
}
|
||||
if let Placeable {
|
||||
expression:
|
||||
Expression::Inline(InlineExpression::StringLiteral { ref value }),
|
||||
} = element
|
||||
{
|
||||
result.push_str(value);
|
||||
}
|
||||
}
|
||||
return Some(result);
|
||||
|
|
@ -422,7 +490,8 @@ impl MDWriter<'_, '_> {
|
|||
/// # Errors
|
||||
/// Returns an error if the writer fails.
|
||||
fn usage(&mut self) -> io::Result<()> {
|
||||
if let Some(usage) = self.extract_fluent_value(&format!("{}-usage", self.name)) {
|
||||
if let Some(usage) = self.extract_fluent_value(&format!("{}-usage", self.fluent_key)) {
|
||||
let usage = fix_usage(self.name, usage);
|
||||
writeln!(self.w, "\n```")?;
|
||||
writeln!(self.w, "{usage}")?;
|
||||
writeln!(self.w, "```")
|
||||
|
|
@ -434,7 +503,7 @@ impl MDWriter<'_, '_> {
|
|||
/// # Errors
|
||||
/// Returns an error if the writer fails.
|
||||
fn about(&mut self) -> io::Result<()> {
|
||||
if let Some(about) = self.extract_fluent_value(&format!("{}-about", self.name)) {
|
||||
if let Some(about) = self.extract_fluent_value(&format!("{}-about", self.fluent_key)) {
|
||||
writeln!(self.w, "{about}")
|
||||
} else {
|
||||
Ok(())
|
||||
|
|
@ -444,7 +513,9 @@ impl MDWriter<'_, '_> {
|
|||
/// # Errors
|
||||
/// Returns an error if the writer fails.
|
||||
fn after_help(&mut self) -> io::Result<()> {
|
||||
if let Some(after_help) = self.extract_fluent_value(&format!("{}-after-help", self.name)) {
|
||||
if let Some(after_help) =
|
||||
self.extract_fluent_value(&format!("{}-after-help", self.fluent_key))
|
||||
{
|
||||
writeln!(self.w, "\n\n{after_help}")
|
||||
} else {
|
||||
Ok(())
|
||||
|
|
@ -515,7 +586,7 @@ impl MDWriter<'_, '_> {
|
|||
writeln!(self.w, "</dt>")?;
|
||||
let help_text = arg.get_help().unwrap_or_default().to_string();
|
||||
// Try to resolve Fluent key if it looks like one, otherwise use as-is
|
||||
let resolved_help = if help_text.starts_with(&format!("{}-help-", self.name)) {
|
||||
let resolved_help = if help_text.starts_with(&format!("{}-help-", self.fluent_key)) {
|
||||
self.extract_fluent_value(&help_text).unwrap_or(help_text)
|
||||
} else {
|
||||
help_text
|
||||
|
|
|
|||
|
|
@ -439,7 +439,7 @@ fn uu_app(binary_name: &str) -> (Command, bool) {
|
|||
let usage = translate!("hashsum-usage-specific", "utility_name" => binary_name);
|
||||
command
|
||||
.help_template(uucore::localized_help_template(binary_name))
|
||||
.override_usage(format_usage(&usage))
|
||||
.override_usage(format_usage(&usage).replace("--<digest> ", ""))
|
||||
};
|
||||
|
||||
(command, is_hashsum_bin)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ test-usage = test EXPRESSION
|
|||
test
|
||||
{"[ EXPRESSION ]"}
|
||||
{"[ ]"}
|
||||
{"[ OPTION ]"}
|
||||
{"[ OPTION"}
|
||||
test-after-help = Exit with the status determined by EXPRESSION.
|
||||
|
||||
An omitted EXPRESSION defaults to false.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ test-usage = test EXPRESSION
|
|||
test
|
||||
{"[ EXPRESSION ]"}
|
||||
{"[ ]"}
|
||||
{"[ OPTION ]"}
|
||||
{"[ OPTION"}
|
||||
test-after-help = Quitter avec le statut déterminé par EXPRESSION.
|
||||
|
||||
Une EXPRESSION omise vaut false par défaut.
|
||||
|
|
|
|||
122
tests/test_uudoc.rs
Normal file
122
tests/test_uudoc.rs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
//! Tests on the `uudoc` binary.
|
||||
//!
|
||||
//! To run the uudoc
|
||||
//! ```
|
||||
//! cargo run --bin uudoc --features uudoc
|
||||
//! ```
|
||||
//!
|
||||
//! To run the tests
|
||||
//! ```
|
||||
//! cargo test --features uudoc
|
||||
//! ```
|
||||
#![cfg(feature = "uudoc")]
|
||||
|
||||
use std::env;
|
||||
pub const TESTS_BINARY: &str = env!("CARGO_BIN_EXE_uudoc");
|
||||
|
||||
// Set the environment variable for any tests
|
||||
|
||||
// Use the ctor attribute to run this function before any tests
|
||||
#[ctor::ctor]
|
||||
fn init() {
|
||||
// No need for unsafe here
|
||||
unsafe {
|
||||
std::env::set_var("UUTESTS_BINARY_PATH", TESTS_BINARY);
|
||||
}
|
||||
// Print for debugging
|
||||
eprintln!("Setting UUTESTS_BINARY_PATH={TESTS_BINARY}");
|
||||
}
|
||||
|
||||
/// Run the `uudoc` command and return the output as a vector of strings.
|
||||
/// # Errors
|
||||
/// If the command fails to execute or if the output cannot be converted to UTF-8, an `io::Error` is returned.
|
||||
fn run_write_doc() -> Vec<String> {
|
||||
use std::process::Command;
|
||||
use uutests::util::TestScenario;
|
||||
|
||||
let scenario = TestScenario::new("");
|
||||
let output = Command::new(&scenario.bin_path).output().unwrap();
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"uudoc command failed: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
|
||||
String::from_utf8(output.stdout)
|
||||
.unwrap()
|
||||
.lines()
|
||||
.map(String::from)
|
||||
.filter(|line| line.starts_with("Wrote"))
|
||||
.collect::<Vec<String>>()
|
||||
}
|
||||
|
||||
fn get_doc_file_from_output(output: &str) -> (String, String) {
|
||||
let correct_path_test = output
|
||||
.strip_prefix("Wrote to '")
|
||||
.unwrap()
|
||||
.strip_suffix("'")
|
||||
.unwrap()
|
||||
.to_string();
|
||||
let content = std::fs::read_to_string(&correct_path_test);
|
||||
let content = match content {
|
||||
Ok(content) => content,
|
||||
Err(e) => {
|
||||
panic!(
|
||||
"Failed to read file {}: {} from {:?}",
|
||||
correct_path_test,
|
||||
e,
|
||||
env::current_dir()
|
||||
);
|
||||
}
|
||||
};
|
||||
(correct_path_test, content)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uudoc_check_test() {
|
||||
let pages = run_write_doc();
|
||||
// assert wrote to the correct file
|
||||
let path_test = pages.iter().find(|line| line.contains("test.md")).unwrap();
|
||||
let (correct_path, content) = get_doc_file_from_output(path_test);
|
||||
|
||||
// open the file
|
||||
assert!(
|
||||
content.contains(
|
||||
"```
|
||||
test EXPRESSION
|
||||
test
|
||||
[ EXPRESSION ]
|
||||
[ ]
|
||||
[ OPTION
|
||||
```
|
||||
",
|
||||
),
|
||||
"{correct_path} does not contains the required text"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uudoc_check_sums() {
|
||||
let pages = run_write_doc();
|
||||
let sums = [
|
||||
"md5sum",
|
||||
"sha1sum",
|
||||
"sha224sum",
|
||||
"sha256sum",
|
||||
"sha384sum",
|
||||
"sha512sum",
|
||||
"b2sum",
|
||||
];
|
||||
for one_sum in sums {
|
||||
let output_path = pages
|
||||
.iter()
|
||||
.find(|one_line| one_line.contains(one_sum))
|
||||
.unwrap();
|
||||
let (correct_path, content) = get_doc_file_from_output(output_path);
|
||||
let formatted = format!("```\n{one_sum} [OPTIONS]... [FILE]...\n```");
|
||||
assert!(
|
||||
content.contains(&formatted),
|
||||
"Content of {correct_path} does not contain the expected format: {formatted}",
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue