use vb6core::error::{err_number, VBError, VBResult};
use crate::value::{VBLong, VBString};
pub fn mid_statement(
stringvar: &VBString,
start: &VBLong,
length: Option<&VBLong>,
string: &VBString,
) -> VBResult<VBString> {
let start = start.as_i32();
if start < 1 {
return Err(VBError::with_description(
err_number::INVALID_PROCEDURE_CALL,
"Invalid start position",
));
}
let max_replace = match length {
Some(n) => {
let n = n.as_i32();
if n < 0 {
return Err(VBError::with_description(
err_number::INVALID_PROCEDURE_CALL,
"Invalid length",
));
}
n as usize
}
None => usize::MAX,
};
let mut target: Vec<char> = stringvar.as_str().chars().collect();
let offset = (start - 1) as usize;
if offset >= target.len() {
return Ok(stringvar.clone());
}
let replacement: Vec<char> = string.as_str().chars().collect();
let take = max_replace
.min(replacement.len())
.min(target.len() - offset);
target.splice(offset..offset + take, replacement[..take].iter().copied());
Ok(VBString::from(target.into_iter().collect::<String>()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn replaces_with_explicit_length() {
assert_eq!(
mid_statement(
&VBString::from("Hello World"),
&VBLong::from(7),
Some(&VBLong::from(5)),
&VBString::from("VB6!!")
)
.unwrap(),
VBString::from("Hello VB6!!")
);
}
#[test]
fn omitted_length_replaces_to_the_end() {
assert_eq!(
mid_statement(
&VBString::from("ABCDEFGH"),
&VBLong::from(3),
None,
&VBString::from("123")
)
.unwrap(),
VBString::from("AB123FGH")
);
assert_eq!(
mid_statement(
&VBString::from("ABCDEFGH"),
&VBLong::from(3),
None,
&VBString::from("1234567890")
)
.unwrap(),
VBString::from("AB123456")
);
}
#[test]
fn shorter_replacement_keeps_the_tail() {
assert_eq!(
mid_statement(
&VBString::from("Test"),
&VBLong::from(2),
Some(&VBLong::from(2)),
&VBString::from("XX")
)
.unwrap(),
VBString::from("TXXt")
);
}
#[test]
fn start_beyond_the_length_is_a_noop() {
assert_eq!(
mid_statement(
&VBString::from("abc"),
&VBLong::from(10),
None,
&VBString::from("xyz")
)
.unwrap(),
VBString::from("abc")
);
}
#[test]
fn rejects_start_below_one() {
assert_eq!(
mid_statement(
&VBString::from("abc"),
&VBLong::from(0),
None,
&VBString::from("x")
)
.unwrap_err()
.number,
err_number::INVALID_PROCEDURE_CALL
);
}
#[test]
fn rejects_negative_length() {
assert_eq!(
mid_statement(
&VBString::from("abc"),
&VBLong::from(1),
Some(&VBLong::from(-1)),
&VBString::from("x")
)
.unwrap_err()
.number,
err_number::INVALID_PROCEDURE_CALL
);
}
#[test]
fn counts_characters_not_bytes() {
assert_eq!(
mid_statement(
&VBString::from("ééééé"),
&VBLong::from(2),
Some(&VBLong::from(2)),
&VBString::from("XY")
)
.unwrap(),
VBString::from("éXYéé")
);
}
}