use proptest::prelude::*;
use rustrade_backtest::load_csv_str;
fn assert_candles_clean(input: &str) {
if let Ok(candles) = load_csv_str(input) {
for c in candles {
assert!(c.open.is_finite() && c.open > 0.0);
assert!(c.high.is_finite() && c.high > 0.0);
assert!(c.low.is_finite() && c.low > 0.0);
assert!(c.close.is_finite() && c.close > 0.0);
assert!(c.volume.is_finite() && c.volume >= 0.0);
}
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(2048))]
#[test]
fn arbitrary_bytes_never_panic(bytes in prop::collection::vec(any::<u8>(), 0..512)) {
let s = String::from_utf8_lossy(&bytes);
assert_candles_clean(&s);
}
#[test]
fn structured_hostile_rows_never_panic(
rows in prop::collection::vec(
prop::collection::vec(
prop_oneof![
Just("".to_string()),
Just("NaN".to_string()),
Just("inf".to_string()),
Just("-inf".to_string()),
Just("0".to_string()),
Just("-1".to_string()),
Just("1e308".to_string()),
Just("1e-308".to_string()),
Just("99999999999999999999999999".to_string()),
"[a-zA-Z0-9.+\\-eE]{0,12}",
any::<f64>().prop_map(|f| f.to_string()),
any::<i64>().prop_map(|i| i.to_string()),
],
0..8, ),
0..16, )
) {
let mut csv = String::from("time,open,high,low,close,volume\n");
for row in &rows {
csv.push_str(&row.join(","));
csv.push('\n');
}
assert_candles_clean(&csv);
}
#[test]
fn comments_and_blanks_never_panic(
lines in prop::collection::vec(
prop_oneof![
Just("# comment".to_string()),
Just("".to_string()),
Just(" ".to_string()),
"[^\\n]{0,24}",
],
0..24,
)
) {
let mut csv = String::from("time,open,high,low,close,volume\n");
for l in &lines {
csv.push_str(l);
csv.push('\n');
}
assert_candles_clean(&csv);
}
}
#[test]
fn known_adversarial_inputs_never_panic() {
let cases = [
"",
"\n\n\n",
"time,open,high,low,close,volume", "time,open,high,low,close,volume\n", "garbage", "time,open,high,low,close,volume\n,,,,,", "time,open,high,low,close,volume\n1,1,1,1,1", "time,open,high,low,close,volume\n1,1,1,1,1,1,1,1", "time,open,high,low,close,volume\nNaN,NaN,NaN,NaN,NaN,NaN",
"time,open,high,low,close,volume\n0,inf,-inf,1,1,1",
"time,open,high,low,close,volume\n9223372036854775807,1,1,1,1,1",
"\u{feff}time,open,high,low,close,volume\n1,1,1,1,1,1", "time,open,high,low,close,volume\n1,1,1,1,1,1\0", ];
for c in cases {
assert_candles_clean(c);
}
}