#![no_main] use arbitrary::{Arbitrary, Result, Unstructured}; use libfuzzer_sys::fuzz_target; use std::str; use tui_textarea::{CursorMove, Input, TextArea}; use tui_textarea_bench::{dummy_terminal, TerminalExt}; #[derive(Arbitrary)] enum RandomInput { Input(Input), InputWithoutShortcuts(Input), Cursor(CursorMove), } impl RandomInput { fn apply(self, t: &mut TextArea<'_>) { match self { Self::Input(input) => { t.input(input); } Self::InputWithoutShortcuts(input) => { t.input_without_shortcuts(input); } Self::Cursor(m) => t.move_cursor(m), } } } fn assert_invariants(textarea: &TextArea<'_>) { let lines = textarea.lines(); assert!(!lines.is_empty(), "lines must never be empty"); let (row, col) = textarea.cursor(); assert!( row < lines.len(), "cursor row {row} out of bounds (lines: {})", lines.len() ); assert!( col <= lines[row].chars().count(), "cursor col {col} out of bounds (line {row} chars: {})", lines[row].chars().count(), ); } fn fuzz(data: &[u8]) -> Result<()> { let mut term = dummy_terminal(); let mut data = Unstructured::new(data); let text = <&str>::arbitrary(&mut data)?; let mut textarea = TextArea::from(text.lines()); for _ in 0..100 { let input = RandomInput::arbitrary(&mut data)?; input.apply(&mut textarea); term.draw_textarea(&textarea); assert_invariants(&textarea); } Ok(()) } fuzz_target!(|data: &[u8]| { let _ = fuzz(data); });