Merge pull request #2272 from miDeb/expr-substr

expr: make substr infallible
This commit is contained in:
Sylvestre Ledru 2021-05-24 00:11:59 +02:00 committed by GitHub
commit 9f73a9faf4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 24 deletions

View file

@ -153,7 +153,7 @@ impl AstNode {
":" | "match" => operator_match(&operand_values),
"length" => Ok(prefix_operator_length(&operand_values)),
"index" => Ok(prefix_operator_index(&operand_values)),
"substr" => prefix_operator_substr(&operand_values),
"substr" => Ok(prefix_operator_substr(&operand_values)),
_ => Err(format!("operation not implemented: {}", op_type)),
},
@ -522,35 +522,23 @@ fn prefix_operator_index(values: &[String]) -> String {
"0".to_string()
}
fn prefix_operator_substr(values: &[String]) -> Result<String, String> {
fn prefix_operator_substr(values: &[String]) -> String {
assert!(values.len() == 3);
let subj = &values[0];
let mut idx = match values[1].parse::<i64>() {
Ok(i) => i,
Err(_) => return Err("expected integer as POS arg to 'substr'".to_string()),
let idx = match values[1]
.parse::<usize>()
.ok()
.and_then(|v| v.checked_sub(1))
{
Some(i) => i,
None => return String::new(),
};
let mut len = match values[2].parse::<i64>() {
let len = match values[2].parse::<usize>() {
Ok(i) => i,
Err(_) => return Err("expected integer as LENGTH arg to 'substr'".to_string()),
Err(_) => return String::new(),
};
if idx <= 0 || len <= 0 {
return Ok("".to_string());
}
let mut out_str = String::new();
for ch in subj.chars() {
idx -= 1;
if idx <= 0 {
if len <= 0 {
break;
}
len -= 1;
out_str.push(ch);
}
}
Ok(out_str)
subj.chars().skip(idx).take(len).collect()
}
fn bool_as_int(b: bool) -> i64 {

View file

@ -54,3 +54,32 @@ fn test_and() {
new_ucmd!().args(&["", "&", "1"]).run().stdout_is("0\n");
}
#[test]
fn test_substr() {
new_ucmd!()
.args(&["substr", "abc", "1", "1"])
.succeeds()
.stdout_only("a\n");
}
#[test]
fn test_invalid_substr() {
new_ucmd!()
.args(&["substr", "abc", "0", "1"])
.fails()
.status_code(1)
.stdout_only("\n");
new_ucmd!()
.args(&["substr", "abc", &(std::usize::MAX.to_string() + "0"), "1"])
.fails()
.status_code(1)
.stdout_only("\n");
new_ucmd!()
.args(&["substr", "abc", "0", &(std::usize::MAX.to_string() + "0")])
.fails()
.status_code(1)
.stdout_only("\n");
}