Merge pull request #2131 from ricardoaiglesias/base32-clap

Base32 clap
This commit is contained in:
Sylvestre Ledru 2021-04-27 09:20:45 +02:00 committed by GitHub
commit 30cf6ec235
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 238 additions and 82 deletions

3
Cargo.lock generated
View file

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "advapi32-sys"
version = "0.2.0"
@ -1653,6 +1655,7 @@ dependencies = [
name = "uu_base32"
version = "0.0.6"
dependencies = [
"clap",
"uucore",
"uucore_procs",
]

View file

@ -15,6 +15,7 @@ edition = "2018"
path = "src/base32.rs"
[dependencies]
clap = "2.33"
uucore = { version=">=0.0.8", package="uucore", path="../../uucore", features = ["encoding"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }

View file

@ -10,9 +10,14 @@ extern crate uucore;
use uucore::encoding::Format;
use uucore::InvalidEncodingHandling;
use std::fs::File;
use std::io::{stdin, BufReader};
use std::path::Path;
use clap::{App, Arg};
mod base_common;
static SYNTAX: &str = "[OPTION]... [FILE]";
static SUMMARY: &str = "Base32 encode or decode FILE, or standard input, to standard output.";
static LONG_HELP: &str = "
With no FILE, or when FILE is -, read standard input.
@ -23,14 +28,128 @@ static LONG_HELP: &str = "
to attempt to recover from any other non-alphabet bytes in the
encoded stream.
";
static VERSION: &str = env!("CARGO_PKG_VERSION");
fn get_usage() -> String {
format!("{0} [OPTION]... [FILE]", executable!())
}
pub mod options {
pub static DECODE: &str = "decode";
pub static WRAP: &str = "wrap";
pub static IGNORE_GARBAGE: &str = "ignore-garbage";
pub static FILE: &str = "file";
}
struct Config {
decode: bool,
ignore_garbage: bool,
wrap_cols: Option<usize>,
to_read: Option<String>,
}
impl Config {
fn from(options: clap::ArgMatches) -> Config {
let file: Option<String> = match options.values_of(options::FILE) {
Some(mut values) => {
let name = values.next().unwrap();
if values.len() != 0 {
crash!(3, "extra operand {}", name);
}
if name == "-" {
None
} else {
if !Path::exists(Path::new(name)) {
crash!(2, "{}: No such file or directory", name);
}
Some(name.to_owned())
}
}
None => None,
};
let cols = match options.value_of(options::WRAP) {
Some(num) => match num.parse::<usize>() {
Ok(n) => Some(n),
Err(e) => {
crash!(1, "invalid wrap size: {}: {}", num, e);
}
},
None => None,
};
Config {
decode: options.is_present(options::DECODE),
ignore_garbage: options.is_present(options::IGNORE_GARBAGE),
wrap_cols: cols,
to_read: file,
}
}
}
pub fn uumain(args: impl uucore::Args) -> i32 {
base_common::execute(
args.collect_str(InvalidEncodingHandling::ConvertLossy)
.accept_any(),
SYNTAX,
SUMMARY,
LONG_HELP,
Format::Base32,
)
let format = Format::Base32;
let usage = get_usage();
let app = App::new(executable!())
.version(VERSION)
.about(SUMMARY)
.usage(&usage[..])
.about(LONG_HELP)
// Format arguments.
.arg(
Arg::with_name(options::DECODE)
.short("d")
.long(options::DECODE)
.help("decode data"),
)
.arg(
Arg::with_name(options::IGNORE_GARBAGE)
.short("i")
.long(options::IGNORE_GARBAGE)
.help("when decoding, ignore non-alphabetic characters"),
)
.arg(
Arg::with_name(options::WRAP)
.short("w")
.long(options::WRAP)
.takes_value(true)
.help(
"wrap encoded lines after COLS character (default 76, 0 to disable wrapping)",
),
)
// "multiple" arguments are used to check whether there is more than one
// file passed in.
.arg(Arg::with_name(options::FILE).index(1).multiple(true));
let arg_list = args
.collect_str(InvalidEncodingHandling::ConvertLossy)
.accept_any();
let config: Config = Config::from(app.get_matches_from(arg_list));
match config.to_read {
// Read from file.
Some(name) => {
let file_buf = safe_unwrap!(File::open(Path::new(&name)));
let mut input = BufReader::new(file_buf);
base_common::handle_input(
&mut input,
format,
config.wrap_cols,
config.ignore_garbage,
config.decode,
);
}
// stdin
None => {
base_common::handle_input(
&mut stdin().lock(),
format,
config.wrap_cols,
config.ignore_garbage,
config.decode,
);
}
};
0
}

View file

@ -7,68 +7,11 @@
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
use std::fs::File;
use std::io::{stdin, stdout, BufReader, Read, Write};
use std::path::Path;
use std::io::{stdout, Read, Write};
use uucore::encoding::{wrap_print, Data, Format};
pub fn execute(
args: Vec<String>,
syntax: &str,
summary: &str,
long_help: &str,
format: Format,
) -> i32 {
let matches = app!(syntax, summary, long_help)
.optflag("d", "decode", "decode data")
.optflag(
"i",
"ignore-garbage",
"when decoding, ignore non-alphabetic characters",
)
.optopt(
"w",
"wrap",
"wrap encoded lines after COLS character (default 76, 0 to disable wrapping)",
"COLS",
)
.parse(args);
let line_wrap = matches.opt_str("wrap").map(|s| match s.parse() {
Ok(n) => n,
Err(e) => {
crash!(1, "invalid wrap size: {}: {}", s, e);
}
});
let ignore_garbage = matches.opt_present("ignore-garbage");
let decode = matches.opt_present("decode");
if matches.free.len() > 1 {
show_usage_error!("extra operand {}", matches.free[0]);
return 1;
}
if matches.free.is_empty() || &matches.free[0][..] == "-" {
let stdin_raw = stdin();
handle_input(
&mut stdin_raw.lock(),
format,
line_wrap,
ignore_garbage,
decode,
);
} else {
let path = Path::new(matches.free[0].as_str());
let file_buf = safe_unwrap!(File::open(&path));
let mut input = BufReader::new(file_buf);
handle_input(&mut input, format, line_wrap, ignore_garbage, decode);
};
0
}
fn handle_input<R: Read>(
pub fn handle_input<R: Read>(
input: &mut R,
format: Format,
line_wrap: Option<usize>,

View file

@ -28,7 +28,9 @@ static SUMMARY: &str = "A lightweight 'finger' program; print user information.
const BUFSIZE: usize = 1024;
pub fn uumain(args: impl uucore::Args) -> i32 {
let args = args.collect_str(InvalidEncodingHandling::Ignore).accept_any();
let args = args
.collect_str(InvalidEncodingHandling::Ignore)
.accept_any();
let long_help = &format!(
"

View file

@ -15,6 +15,21 @@ fn test_encode() {
.pipe_in(input)
.succeeds()
.stdout_only("JBSWY3DPFQQFO33SNRSCC===\n");
// Using '-' as our file
new_ucmd!()
.arg("-")
.pipe_in(input)
.succeeds()
.stdout_only("JBSWY3DPFQQFO33SNRSCC===\n");
}
#[test]
fn test_base32_encode_file() {
new_ucmd!()
.arg("input-simple.txt")
.succeeds()
.stdout_only("JBSWY3DPFQQFO33SNRSCCCQ=\n");
}
#[test]
@ -71,8 +86,7 @@ fn test_wrap() {
fn test_wrap_no_arg() {
for wrap_param in vec!["-w", "--wrap"] {
new_ucmd!().arg(wrap_param).fails().stderr_only(format!(
"base32: error: Argument to option '{}' missing\n",
if wrap_param == "-w" { "w" } else { "wrap" }
"error: The argument '--wrap <wrap>\' requires a value but none was supplied\n\nUSAGE:\n base32 [OPTION]... [FILE]\n\nFor more information try --help"
));
}
}
@ -87,3 +101,21 @@ fn test_wrap_bad_arg() {
.stderr_only("base32: error: invalid wrap size: b: invalid digit found in string\n");
}
}
#[test]
fn test_base32_extra_operand() {
// Expect a failure when multiple files are specified.
new_ucmd!()
.arg("a.txt")
.arg("a.txt")
.fails()
.stderr_only("base32: error: extra operand a.txt");
}
#[test]
fn test_base32_file_not_found() {
new_ucmd!()
.arg("a.txt")
.fails()
.stderr_only("base32: error: a.txt: No such file or directory");
}

View file

@ -13,7 +13,12 @@ fn test_increase_file_size() {
file.seek(SeekFrom::End(0)).unwrap();
let actual = file.seek(SeekFrom::Current(0)).unwrap();
assert!(expected == actual, "expected '{}' got '{}'", expected, actual);
assert!(
expected == actual,
"expected '{}' got '{}'",
expected,
actual
);
}
#[test]
@ -25,7 +30,12 @@ fn test_increase_file_size_kb() {
file.seek(SeekFrom::End(0)).unwrap();
let actual = file.seek(SeekFrom::Current(0)).unwrap();
assert!(expected == actual, "expected '{}' got '{}'", expected, actual);
assert!(
expected == actual,
"expected '{}' got '{}'",
expected,
actual
);
}
#[test]
@ -46,7 +56,12 @@ fn test_reference() {
file.seek(SeekFrom::End(0)).unwrap();
let actual = file.seek(SeekFrom::Current(0)).unwrap();
assert!(expected == actual, "expected '{}' got '{}'", expected, actual);
assert!(
expected == actual,
"expected '{}' got '{}'",
expected,
actual
);
}
#[test]
@ -58,7 +73,12 @@ fn test_decrease_file_size() {
ucmd.args(&["--size=-4", TFILE2]).succeeds();
file.seek(SeekFrom::End(0)).unwrap();
let actual = file.seek(SeekFrom::Current(0)).unwrap();
assert!(expected == actual, "expected '{}' got '{}'", expected, actual);
assert!(
expected == actual,
"expected '{}' got '{}'",
expected,
actual
);
}
#[test]
@ -70,7 +90,12 @@ fn test_space_in_size() {
ucmd.args(&["--size", " 4", TFILE2]).succeeds();
file.seek(SeekFrom::End(0)).unwrap();
let actual = file.seek(SeekFrom::Current(0)).unwrap();
assert!(expected == actual, "expected '{}' got '{}'", expected, actual);
assert!(
expected == actual,
"expected '{}' got '{}'",
expected,
actual
);
}
#[test]
@ -99,7 +124,12 @@ fn test_at_most_shrinks() {
ucmd.args(&["--size", "<4", TFILE2]).succeeds();
file.seek(SeekFrom::End(0)).unwrap();
let actual = file.seek(SeekFrom::Current(0)).unwrap();
assert!(expected == actual, "expected '{}' got '{}'", expected, actual);
assert!(
expected == actual,
"expected '{}' got '{}'",
expected,
actual
);
}
#[test]
@ -111,7 +141,12 @@ fn test_at_most_no_change() {
ucmd.args(&["--size", "<40", TFILE2]).succeeds();
file.seek(SeekFrom::End(0)).unwrap();
let actual = file.seek(SeekFrom::Current(0)).unwrap();
assert!(expected == actual, "expected '{}' got '{}'", expected, actual);
assert!(
expected == actual,
"expected '{}' got '{}'",
expected,
actual
);
}
#[test]
@ -123,7 +158,12 @@ fn test_at_least_grows() {
ucmd.args(&["--size", ">15", TFILE2]).succeeds();
file.seek(SeekFrom::End(0)).unwrap();
let actual = file.seek(SeekFrom::Current(0)).unwrap();
assert!(expected == actual, "expected '{}' got '{}'", expected, actual);
assert!(
expected == actual,
"expected '{}' got '{}'",
expected,
actual
);
}
#[test]
@ -135,7 +175,12 @@ fn test_at_least_no_change() {
ucmd.args(&["--size", ">4", TFILE2]).succeeds();
file.seek(SeekFrom::End(0)).unwrap();
let actual = file.seek(SeekFrom::Current(0)).unwrap();
assert!(expected == actual, "expected '{}' got '{}'", expected, actual);
assert!(
expected == actual,
"expected '{}' got '{}'",
expected,
actual
);
}
#[test]
@ -147,7 +192,12 @@ fn test_round_down() {
ucmd.args(&["--size", "/4", TFILE2]).succeeds();
file.seek(SeekFrom::End(0)).unwrap();
let actual = file.seek(SeekFrom::Current(0)).unwrap();
assert!(expected == actual, "expected '{}' got '{}'", expected, actual);
assert!(
expected == actual,
"expected '{}' got '{}'",
expected,
actual
);
}
#[test]
@ -159,5 +209,10 @@ fn test_round_up() {
ucmd.args(&["--size", "*4", TFILE2]).succeeds();
file.seek(SeekFrom::End(0)).unwrap();
let actual = file.seek(SeekFrom::Current(0)).unwrap();
assert!(expected == actual, "expected '{}' got '{}'", expected, actual);
assert!(
expected == actual,
"expected '{}' got '{}'",
expected,
actual
);
}

View file

@ -0,0 +1 @@
Hello, World!