Do some automated random testing of Rope
This commit is contained in:
parent
454e2f12fe
commit
2b959e5a68
|
|
@ -5,3 +5,4 @@ edition = "2021"
|
|||
|
||||
[dev-dependencies]
|
||||
ntest = "0.9.3"
|
||||
rand = {version="0.8.5", features=["small_rng"]}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use {super::fibbonacci::fibbonacci, std::rc::Rc};
|
||||
use super::fibbonacci::fibbonacci;
|
||||
pub use std::rc::Rc;
|
||||
|
||||
/// [Rope](https://en.wikipedia.org/wiki/Rope_(data_structure)) data structure
|
||||
/// implementation.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
use super::super::{Rc, Rope};
|
||||
use rand::{
|
||||
distributions::{Alphanumeric, DistString},
|
||||
rngs::SmallRng,
|
||||
Rng, SeedableRng,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Command {
|
||||
InsertAtCharIndex { index: usize, text: String },
|
||||
DeleteAtCharIndex { index: usize, length: usize },
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn run(&self, rope: &Rc<Rope>) -> Rc<Rope> {
|
||||
match self {
|
||||
Command::InsertAtCharIndex { index, text } => rope.insert_at_char_index(*index, text),
|
||||
Command::DeleteAtCharIndex { index, length } => {
|
||||
rope.delete_at_char_index(*index, *length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_on_string(&self, input: String) -> String {
|
||||
match self {
|
||||
Command::InsertAtCharIndex { index, text } => input
|
||||
.chars()
|
||||
.take(*index)
|
||||
.chain(text.chars())
|
||||
.chain(input.chars().skip(*index))
|
||||
.collect(),
|
||||
Command::DeleteAtCharIndex { index, length } => input
|
||||
.chars()
|
||||
.enumerate()
|
||||
.filter(|(i, _)| *i < *index || *i >= index + length)
|
||||
.map(|(_, c)| c)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Alphanumeric only samples ASCII
|
||||
pub fn generate_random_edit_sequence_with_seed(
|
||||
length: usize,
|
||||
seed: u64,
|
||||
) -> (String, Vec<(Command, String)>) {
|
||||
let mut rng = SmallRng::seed_from_u64(seed);
|
||||
let start_text_length = rng.gen_range(0..4000);
|
||||
let start_text = Alphanumeric.sample_string(&mut rng, start_text_length);
|
||||
let num_steps = rng.gen_range(0..1000);
|
||||
let mut steps = Vec::with_capacity(num_steps);
|
||||
let mut current_text = start_text.clone();
|
||||
for i in 0..num_steps {
|
||||
let current_text_length = current_text.len();
|
||||
let command = if rng.gen_bool(0.7) || current_text_length > 0 {
|
||||
let index = rng.gen_range(0..current_text_length);
|
||||
let text_len = rng.gen_range(0..100);
|
||||
let text = Alphanumeric.sample_string(&mut rng, text_len);
|
||||
Command::InsertAtCharIndex { index, text }
|
||||
} else {
|
||||
let index = rng.gen_range(0..current_text_length-1);
|
||||
let length = rng.gen_range(1..(current_text_length - index));
|
||||
Command::DeleteAtCharIndex { index, length }
|
||||
};
|
||||
current_text = command.run_on_string(current_text);
|
||||
steps.push((command.clone(), current_text.clone()));
|
||||
}
|
||||
(start_text, steps)
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
use super::*;
|
||||
use ntest::timeout;
|
||||
|
||||
mod command_list;
|
||||
|
||||
fn small_test_rope() -> Rc<Rope> {
|
||||
Rope::join(
|
||||
Rope::join(
|
||||
|
|
@ -469,3 +471,96 @@ fn char_iterator_reports_correct_point() {
|
|||
assert_eq!(found.column, expected_column);
|
||||
}
|
||||
}
|
||||
|
||||
// Run multiple tests with different seeds so that `cargo test` will run them in
|
||||
// parallel.
|
||||
// TODO: This could use a macro to generate the list of tests.
|
||||
fn random_insertions_and_deletions_with_seed(seed: u64) {
|
||||
let (start_text, edits) = command_list::generate_random_edit_sequence_with_seed(1000, seed);
|
||||
let mut target = Rope::new(start_text);
|
||||
for (command, expected_text) in edits {
|
||||
println!("{:?}", command);
|
||||
target = command.run(&target);
|
||||
assert_eq!(expected_text, target.iter_chars().collect::<String>());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_1() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_2() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0002);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_3() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0003);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_4() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0004);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_5() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0005);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_6() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0006);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_7() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0007);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_8() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0008);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_9() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0009);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_10() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0010);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_11() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0011);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_12() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0012);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_13() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0013);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_14() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0014);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_15() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0015);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_insertions_and_deletions_16() {
|
||||
random_insertions_and_deletions_with_seed(0x1234567890ab0016);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue