requestty 0.6.3

An easy-to-use collection of interactive cli prompts
Documentation
use rand::prelude::*;
use rand_chacha::ChaCha12Rng;
use ui::{backend::TestBackend, events::KeyCode, layout::Layout};

use crate::question::{Choice, Question, QuestionKind};

use super::*;

const SEED: u64 = 9828123;
const SEP_RATIO: f32 = 0.3;
const DEFAULT_SEP_RATIO: f32 = 0.10;

fn choices(len: usize) -> impl Iterator<Item = Choice<String>> {
    let mut rng = ChaCha12Rng::seed_from_u64(SEED);

    (0..len).map(move |i| {
        let rand: f32 = rng.gen();
        if rand < DEFAULT_SEP_RATIO {
            Choice::DefaultSeparator
        } else if rand < SEP_RATIO {
            Choice::Separator(format!("Separator {}", i))
        } else {
            Choice::Choice(format!("Choice {}", i))
        }
    })
}

fn unwrap_select<'a>(question: impl Into<Question<'a>>) -> RawSelect<'a> {
    match question.into().kind {
        QuestionKind::RawSelect(s) => s,
        _ => unreachable!(),
    }
}

fn raw_select(message: &str) -> RawSelectPrompt<'_> {
    unwrap_select(RawSelectBuilder::new("name".into()).choices(choices(10))).into_prompt(message)
}

#[test]
fn test_render() {
    let size = (50, 20).into();
    let base_layout = Layout::new(0, size);
    let mut backend = TestBackend::new_with_layout(size, base_layout);

    let mut raw_select = raw_select("message");

    let keys = [
        (KeyEvent::from(KeyCode::Down), 11),
        (KeyEvent::from(KeyCode::Delete), 10),
        (KeyEvent::from(KeyCode::Char('6')), 11),
    ];

    let mut layout = base_layout;
    assert!(raw_select.render(&mut layout, &mut backend).is_ok());
    ui::assert_backend_snapshot!(backend);
    assert_eq!(layout, base_layout.with_offset(0, 11).with_line_offset(10));

    for &(key, line_offset) in keys.iter() {
        layout = base_layout;
        backend.reset_with_layout(layout);
        assert!(raw_select.handle_key(key));
        assert!(raw_select.render(&mut layout, &mut backend).is_ok());
        ui::assert_backend_snapshot!(backend);
        assert_eq!(
            layout,
            base_layout.with_offset(0, 11).with_line_offset(line_offset)
        );
    }
}

#[test]
fn test_height() {
    let size = (50, 20).into();
    let base_layout = Layout::new(0, size);

    let mut raw_select = raw_select("message");

    let keys = [
        (KeyEvent::from(KeyCode::Down), 11),
        (KeyEvent::from(KeyCode::Delete), 10),
        (KeyEvent::from(KeyCode::Char('6')), 11),
    ];

    let mut layout = base_layout;
    assert_eq!(raw_select.height(&mut layout), 12);
    assert_eq!(layout, base_layout.with_offset(0, 11).with_line_offset(10));

    for &(key, line_offset) in keys.iter() {
        layout = base_layout;
        assert!(raw_select.handle_key(key));
        assert_eq!(raw_select.height(&mut layout), 12);
        assert_eq!(
            layout,
            base_layout.with_offset(0, 11).with_line_offset(line_offset)
        );
    }
}

#[test]
fn test_cursor_pos() {
    let size = (50, 20).into();
    let layout = Layout::new(5, size);

    let mut select = raw_select("message");

    let keys = [
        (KeyEvent::from(KeyCode::Down), 10),
        (KeyEvent::from(KeyCode::Delete), 10),
        (KeyEvent::from(KeyCode::Char('6')), 11),
    ];

    assert_eq!(select.cursor_pos(layout), (10, 11));

    for &(key, line_offset) in keys.iter() {
        assert!(select.handle_key(key));
        assert_eq!(select.cursor_pos(layout), (line_offset, 11));
    }

    let message = "-".repeat(size.width as usize) + "message";
    let mut select = raw_select(&message);

    assert_eq!(select.cursor_pos(layout), (10, 12));

    for &(key, line_offset) in keys.iter() {
        assert!(select.handle_key(key));
        assert_eq!(select.cursor_pos(layout), (line_offset, 12));
    }
}