summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Tay <sam.chong.tay@gmail.com>2020-07-15 00:43:55 -0700
committerSam Tay <sam.chong.tay@gmail.com>2020-07-15 00:43:55 -0700
commit06940575afe283c870b559076bc8b41055db061d (patch)
tree39fe51e1fba9e7e92462d1db74a0cba916051a93
parent93c13cdbf3fecaf23f21237ecee42d62f62905e0 (diff)
Add some basic TUI teststui-test
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/tui/app.rs113
-rw-r--r--src/tui/views.rs1
4 files changed, 109 insertions, 7 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f540818..c0ec5d5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2052,6 +2052,7 @@ version = "0.4.2"
dependencies = [
"clap",
"criterion",
+ "crossbeam-channel",
"crossterm",
"cursive",
"directories",
diff --git a/Cargo.toml b/Cargo.toml
index d60e8db..51e30e3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,6 +17,7 @@ travis-ci = { repository = "samtay/so", branch = "master" }
[dev-dependencies]
criterion = "0.3"
+crossbeam-channel = "0.4.2"
[[bench]]
name = "html_parsing"
diff --git a/src/tui/app.rs b/src/tui/app.rs
index bdd4665..70e3fc9 100644
--- a/src/tui/app.rs
+++ b/src/tui/app.rs
@@ -23,8 +23,13 @@ pub const NAME_HELP_VIEW: &str = "help_view";
pub fn run(qs: Vec<Question<Markdown>>) -> Result<()> {
let mut siv = cursive::default();
- siv.load_theme_file(Config::theme_file_path()?).unwrap(); // TODO dont unwrap
+ siv.load_theme_file(Config::theme_file_path()?).unwrap();
+ mk_tui(&mut siv, qs);
+ siv.run();
+ Ok(())
+}
+fn mk_tui(mut siv: &mut Cursive, qs: Vec<Question<Markdown>>) {
let question_map: HashMap<u32, Question<Markdown>> =
qs.clone().into_iter().map(|q| (q.id, q)).collect();
let question_map = Arc::new(question_map);
@@ -71,7 +76,7 @@ pub fn run(qs: Vec<Question<Markdown>>) -> Result<()> {
if let Some(pos) = s.screen_mut().find_layer_from_name(NAME_HELP_VIEW) {
s.screen_mut().remove_layer(pos);
} else {
- s.add_layer(help());
+ s.add_layer(help().add_vim_bindings());
}
});
// Reload theme
@@ -79,8 +84,6 @@ pub fn run(qs: Vec<Question<Markdown>>) -> Result<()> {
s.load_theme_file(Config::theme_file_path().unwrap())
.unwrap()
});
- siv.run();
- Ok(())
}
fn question_selected_callback(
@@ -169,5 +172,103 @@ pub fn help() -> Dialog {
.title("Help")
}
-// TODO see cursive/examples/src/bin/select_test.rs for how to test the interface!
-// maybe see if we can conditionally run when --nocapture is passed?
+#[cfg(test)]
+pub mod tests {
+
+ use cursive::backends::puppet::observed::ObservedScreen;
+ use cursive::event::Event;
+ use cursive::*;
+ use std::cell::RefCell;
+
+ use super::*;
+
+ pub struct BasicTest {
+ siv: Cursive,
+ screen_stream: crossbeam_channel::Receiver<ObservedScreen>,
+ input: crossbeam_channel::Sender<Option<Event>>,
+ last_screen: RefCell<Option<ObservedScreen>>,
+ }
+ impl BasicTest {
+ pub fn new() -> Self {
+ let size = Vec2::new(80, 20);
+ let backend = backends::puppet::Backend::init(Some(size));
+ let sink = backend.stream();
+ let input = backend.input();
+ let mut siv = Cursive::new(|| backend);
+
+ // TODO stub out some q/a
+ mk_tui(
+ &mut siv,
+ vec![Question {
+ id: 1,
+ score: 64,
+ answers: vec![],
+ title: String::from("Is a hamburger a sanwich?"),
+ body: markdown::parse("For **real** though"),
+ }],
+ );
+
+ input.send(Some(Event::Refresh)).unwrap();
+ siv.step();
+
+ BasicTest {
+ siv,
+ screen_stream: sink,
+ input,
+ last_screen: RefCell::new(None),
+ }
+ }
+
+ pub fn last_screen(&self) -> Option<ObservedScreen> {
+ while let Ok(screen) = self.screen_stream.try_recv() {
+ self.last_screen.replace(Some(screen));
+ }
+
+ self.last_screen.borrow().clone()
+ }
+
+ /// Run `cargo test -- --nocapture` to see debug screens
+ pub fn dump_debug(&self) {
+ self.last_screen().as_ref().map(|s| s.print_stdout());
+ }
+
+ pub fn hit_keystroke(&mut self, key: Event) {
+ self.input.send(Some(key)).unwrap();
+ self.siv.step();
+ }
+ }
+
+ #[test]
+ fn test_basic() {
+ let s = BasicTest::new();
+ s.dump_debug();
+
+ // Can see question
+ let screen = s.last_screen().unwrap();
+ assert_eq!(screen.find_occurences("Is a hamburger a sanwich").len(), 1);
+ assert_eq!(screen.find_occurences("For real though").len(), 1);
+ }
+
+ #[test]
+ fn test_help() {
+ let mut s = BasicTest::new();
+
+ // Get help
+ s.hit_keystroke(Event::Char('?'));
+ s.dump_debug();
+ let screen = s.last_screen().unwrap();
+ assert_eq!(screen.find_occurences("Panes").len(), 1);
+
+ // Scroll to bottom
+ s.hit_keystroke(Event::Char('G'));
+ s.dump_debug();
+ let screen = s.last_screen().unwrap();
+ assert_eq!(screen.find_occurences("Toggle this help menu").len(), 1);
+
+ // Close help
+ s.hit_keystroke(Event::Char('?'));
+ s.dump_debug();
+ let screen = s.last_screen().unwrap();
+ assert_eq!(screen.find_occurences("Toggle this help menu").len(), 0);
+ }
+}
diff --git a/src/tui/views.rs b/src/tui/views.rs
index 7d1593d..3d1dbc3 100644
--- a/src/tui/views.rs
+++ b/src/tui/views.rs
@@ -19,7 +19,6 @@ pub const NAME_QUESTION_VIEW: &str = "question_view";
pub const NAME_ANSWER_VIEW: &str = "answer_view";
pub const NAME_FULL_LAYOUT: &str = "full_layout";
-// TODO this seems pointless; probably should be removed
pub enum Name {
QuestionList,
AnswerList,