aboutsummaryrefslogblamecommitdiffstats
path: root/tests/input.rs
blob: 1799cde81eb093e41f0b85a96e9a4863b4092314 (plain) (tree)
1
2
3


                                 























































                                                      

                                                                              



























                                                 


                                              
                         
                                                    

                       
                                                      
                         

                                                           
                        

                                                          


                         

                                                                    
                        
                                                                    
                             

                                                                         
                            


                                                                




                          






























































                                                                         
 















































































































                                                                              
                                                      
                 
                                                 

                       
                                                    
                    
                                                       

             
                                     

       
 
               
                                                                  


                                            
               


                                                                


                                                                   
               
               
                                                                




                                                     
               


                                                                
                                                                    









                                                       
 
#![allow(clippy::collapsible_if)]

use std::io::Write as _;

mod fixtures;

#[test]
fn test_basic() {
    let mut fixture = fixtures::Fixture::new("input");
    fixture.screenguard(false);
    let mut run = fixture.build();

    for utf8 in &[true, false] {
        for ctrl in &[true, false] {
            for meta in &[true, false] {
                for special_keys in &[true, false] {
                    for single in &[true, false] {
                        run_input_test(
                            &mut run,
                            *utf8,
                            *ctrl,
                            *meta,
                            *special_keys,
                            *single,
                        );
                    }
                }
            }
        }
    }
}

#[test]
fn test_async() {
    let mut fixture = fixtures::Fixture::new("input");
    fixture.screenguard(false);
    fixture.features("async");
    let mut run = fixture.build();

    for utf8 in &[true, false] {
        for ctrl in &[true, false] {
            for meta in &[true, false] {
                for special_keys in &[true, false] {
                    for single in &[true, false] {
                        run_input_test(
                            &mut run,
                            *utf8,
                            *ctrl,
                            *meta,
                            *special_keys,
                            *single,
                        );
                    }
                }
            }
        }
    }
}

// the structure of the if statements here are easier to interpret uncollapsed
#[allow(clippy::collapsible_else_if)]
fn run_input_test(
    fixture: &mut fixtures::BuiltFixture,
    utf8: bool,
    ctrl: bool,
    meta: bool,
    special_keys: bool,
    single: bool,
) {
    let mut args = vec![];
    if !utf8 {
        args.push("--disable-utf8")
    }
    if !ctrl {
        args.push("--disable-ctrl")
    }
    if !meta {
        args.push("--disable-meta")
    }
    if !special_keys {
        args.push("--disable-special-keys")
    }
    if !single {
        args.push("--disable-single")
    }

    fixture.run(&args, |pty| {
        let mut r = std::io::BufReader::new(pty);

        assert_no_more_lines(&mut r);

        write(r.get_mut(), textmode::Key::Up);
        if special_keys {
            assert_line(&mut r, "Up: [27, 91, 65]");
        } else {
            if single {
                assert_line(&mut r, "Byte(27): [27]");
                if utf8 {
                    assert_line(&mut r, "Char('['): [91]");
                    assert_line(&mut r, "Char('A'): [65]");
                } else {
                    assert_line(&mut r, "Byte(91): [91]");
                    assert_line(&mut r, "Byte(65): [65]");
                }
            } else {
                if utf8 {
                    assert_line(&mut r, "Bytes([27]): [27]");
                    assert_line(&mut r, "String(\"[A\"): [91, 65]");
                } else {
                    // TODO: ideally this wouldn't make a difference
                    if meta {
                        assert_line(&mut r, "Bytes([27]): [27]");
                        assert_line(&mut r, "Bytes([91, 65]): [91, 65]");
                    } else {
                        assert_line(
                            &mut r,
                            "Bytes([27, 91, 65]): [27, 91, 65]",
                        );
                    }
                }
            }
        }
        assert_no_more_lines(&mut r);

        write(r.get_mut(), textmode::Key::Meta(b'c'));
        if meta {
            assert_line(&mut r, "Meta(99): [27, 99]");
        } else {
            if special_keys {
                assert_line(&mut r, "Escape: [27]");
                if utf8 {
                    if single {
                        assert_line(&mut r, "Char('c'): [99]");
                    } else {
                        assert_line(&mut r, "String(\"c\"): [99]");
                    }
                } else {
                    if single {
                        assert_line(&mut r, "Byte(99): [99]");
                    } else {
                        assert_line(&mut r, "Bytes([99]): [99]");
                    }
                }
            } else {
                if single {
                    assert_line(&mut r, "Byte(27): [27]");
                    if utf8 {
                        assert_line(&mut r, "Char('c'): [99]");
                    } else {
                        assert_line(&mut r, "Byte(99): [99]");
                    }
                } else {
                    if utf8 {
                        assert_line(&mut r, "Bytes([27]): [27]");
                        assert_line(&mut r, "String(\"c\"): [99]");
                    } else {
                        assert_line(&mut r, "Bytes([27, 99]): [27, 99]");
                    }
                }
            }
        }
        assert_no_more_lines(&mut r);

        write(r.get_mut(), textmode::Key::String("foo".to_string()));
        if single {
            if utf8 {
                assert_line(&mut r, "Char('f'): [102]");
                assert_line(&mut r, "Char('o'): [111]");
                assert_line(&mut r, "Char('o'): [111]");
            } else {
                assert_line(&mut r, "Byte(102): [102]");
                assert_line(&mut r, "Byte(111): [111]");
                assert_line(&mut r, "Byte(111): [111]");
            }
        } else {
            if utf8 {
                assert_line(&mut r, "String(\"foo\"): [102, 111, 111]");
            } else {
                assert_line(
                    &mut r,
                    "Bytes([102, 111, 111]): [102, 111, 111]",
                );
            }
        }
        assert_no_more_lines(&mut r);

        write(r.get_mut(), textmode::Key::String("🎉".to_string()));
        if single {
            if utf8 {
                assert_line(&mut r, "Char('🎉'): [240, 159, 142, 137]");
            } else {
                assert_line(&mut r, "Byte(240): [240]");
                assert_line(&mut r, "Byte(159): [159]");
                assert_line(&mut r, "Byte(142): [142]");
                assert_line(&mut r, "Byte(137): [137]");
            }
        } else {
            if utf8 {
                assert_line(&mut r, "String(\"🎉\"): [240, 159, 142, 137]");
            } else {
                assert_line(
                    &mut r,
                    "Bytes([240, 159, 142, 137]): [240, 159, 142, 137]",
                );
            }
        }
        assert_no_more_lines(&mut r);

        write(r.get_mut(), textmode::Key::Bytes(vec![102, 111, 111, 240]));
        if single {
            if utf8 {
                assert_line(&mut r, "Char('f'): [102]");
                assert_line(&mut r, "Char('o'): [111]");
                assert_line(&mut r, "Char('o'): [111]");
            } else {
                assert_line(&mut r, "Byte(102): [102]");
                assert_line(&mut r, "Byte(111): [111]");
                assert_line(&mut r, "Byte(111): [111]");
                assert_line(&mut r, "Byte(240): [240]");
            }
        } else {
            if utf8 {
                assert_line(&mut r, "String(\"foo\"): [102, 111, 111]");
            } else {
                assert_line(
                    &mut r,
                    "Bytes([102, 111, 111, 240]): [102, 111, 111, 240]",
                );
            }
        }
        assert_no_more_lines(&mut r);
        write(r.get_mut(), textmode::Key::Bytes(vec![159]));
        if utf8 {
            assert_no_more_lines(&mut r);
        } else {
            if single {
                assert_line(&mut r, "Byte(159): [159]");
            } else {
                assert_line(&mut r, "Bytes([159]): [159]");
            }
        }
        write(r.get_mut(), textmode::Key::Bytes(vec![142]));
        if utf8 {
            assert_no_more_lines(&mut r);
        } else {
            if single {
                assert_line(&mut r, "Byte(142): [142]");
            } else {
                assert_line(&mut r, "Bytes([142]): [142]");
            }
        }
        write(r.get_mut(), textmode::Key::Bytes(vec![137]));
        if utf8 {
            if single {
                assert_line(&mut r, "Char('🎉'): [240, 159, 142, 137]");
            } else {
                assert_line(&mut r, "String(\"🎉\"): [240, 159, 142, 137]");
            }
        } else {
            if single {
                assert_line(&mut r, "Byte(137): [137]");
            } else {
                assert_line(&mut r, "Bytes([137]): [137]");
            }
        }
        assert_no_more_lines(&mut r);

        write(r.get_mut(), textmode::Key::Bytes(vec![240, 102, 111, 111]));
        if utf8 {
            if single {
                assert_line(&mut r, "Byte(240): [240]");
                assert_line(&mut r, "Char('f'): [102]");
                assert_line(&mut r, "Char('o'): [111]");
                assert_line(&mut r, "Char('o'): [111]");
            } else {
                // TODO: ideally this would be Bytes([240]) followed by
                // String("foo") but figuring that out in a general way seems
                // hard, and this is a pretty minor edge case
                assert_line(
                    &mut r,
                    "Bytes([240, 102, 111, 111]): [240, 102, 111, 111]",
                );
            }
        } else {
            if single {
                assert_line(&mut r, "Byte(240): [240]");
                assert_line(&mut r, "Byte(102): [102]");
                assert_line(&mut r, "Byte(111): [111]");
                assert_line(&mut r, "Byte(111): [111]");
            } else {
                assert_line(
                    &mut r,
                    "Bytes([240, 102, 111, 111]): [240, 102, 111, 111]",
                );
            }
        }
        assert_no_more_lines(&mut r);

        write(r.get_mut(), textmode::Key::Ctrl(b'c'));
        if ctrl {
            assert_line(&mut r, "Ctrl(99): [3]");
        } else {
            if single {
                assert_line(&mut r, "Byte(3): [3]");
            } else {
                assert_line(&mut r, "Bytes([3]): [3]");
            }
        }
        assert_no_more_lines(&mut r);
    });
}

#[track_caller]
fn write(f: &mut pty_process::blocking::Pty, key: textmode::Key) {
    f.write_all(&key.into_bytes()).unwrap();
}

#[track_caller]
fn read(
    f: &mut std::io::BufReader<&mut pty_process::blocking::Pty>,
) -> String {
    std::string::String::from_utf8(fixtures::read_line(f)).unwrap()
}

#[track_caller]
fn assert_line(
    f: &mut std::io::BufReader<&mut pty_process::blocking::Pty>,
    expected: &str,
) {
    assert_eq!(read(f), format!("{}\r\n", expected));
}

#[track_caller]
fn assert_no_more_lines(
    f: &mut std::io::BufReader<&mut pty_process::blocking::Pty>,
) {
    if fixtures::read_ready(f.get_ref()) || !f.buffer().is_empty() {
        use std::io::Read as _;
        let mut buf = vec![0; 4096];
        let bytes = f.read(&mut buf).unwrap();
        buf.truncate(bytes);
        panic!(
            "got bytes: \"{}\"({:?})",
            std::string::String::from_utf8_lossy(&buf),
            buf
        );
    }
}