From 8c5ec95ac0a8535060b9e0545e4c46f57aeccbfd Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Fri, 17 Feb 2023 13:50:00 -0500 Subject: factor write command tests to own module --- helix-term/tests/integration.rs | 1 - helix-term/tests/test/commands.rs | 93 +------- helix-term/tests/test/commands/write.rs | 409 ++++++++++++++++++++++++++++++++ helix-term/tests/test/write.rs | 319 ------------------------- 4 files changed, 410 insertions(+), 412 deletions(-) create mode 100644 helix-term/tests/test/commands/write.rs delete mode 100644 helix-term/tests/test/write.rs diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs index a378af7a..be1bfc2c 100644 --- a/helix-term/tests/integration.rs +++ b/helix-term/tests/integration.rs @@ -23,5 +23,4 @@ mod test { mod movement; mod prompt; mod splits; - mod write; } diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index e8d16bfa..74c32c4a 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -1,99 +1,8 @@ -use std::ops::RangeInclusive; - -use helix_core::diagnostic::Severity; use helix_term::application::Application; use super::*; -#[tokio::test(flavor = "multi_thread")] -async fn test_write_quit_fail() -> anyhow::Result<()> { - let file = helpers::new_readonly_tempfile()?; - let mut app = helpers::AppBuilder::new() - .with_file(file.path(), None) - .build()?; - - test_key_sequence( - &mut app, - Some("ihello:wq"), - Some(&|app| { - let mut docs: Vec<_> = app.editor.documents().collect(); - assert_eq!(1, docs.len()); - - let doc = docs.pop().unwrap(); - assert_eq!(Some(file.path()), doc.path().map(PathBuf::as_path)); - assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); - }), - false, - ) - .await?; - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_buffer_close_concurrent() -> anyhow::Result<()> { - test_key_sequences( - &mut helpers::AppBuilder::new().build()?, - vec![ - ( - None, - Some(&|app| { - assert_eq!(1, app.editor.documents().count()); - assert!(!app.editor.is_err()); - }), - ), - ( - Some("ihello:new"), - Some(&|app| { - assert_eq!(2, app.editor.documents().count()); - assert!(!app.editor.is_err()); - }), - ), - ( - Some(":bufferclose"), - Some(&|app| { - assert_eq!(1, app.editor.documents().count()); - assert!(!app.editor.is_err()); - }), - ), - ], - false, - ) - .await?; - - // verify if writes are queued up, it finishes them before closing the buffer - let mut file = tempfile::NamedTempFile::new()?; - let mut command = String::new(); - const RANGE: RangeInclusive = 1..=1000; - - for i in RANGE { - let cmd = format!("%c{}:w!", i); - command.push_str(&cmd); - } - - command.push_str(":bufferclose"); - - let mut app = helpers::AppBuilder::new() - .with_file(file.path(), None) - .build()?; - - test_key_sequence( - &mut app, - Some(&command), - Some(&|app| { - assert!(!app.editor.is_err(), "error: {:?}", app.editor.get_status()); - - let doc = app.editor.document_by_path(file.path()); - assert!(doc.is_none(), "found doc: {:?}", doc); - }), - false, - ) - .await?; - - helpers::assert_file_has_content(file.as_file_mut(), &RANGE.end().to_string())?; - - Ok(()) -} +mod write; #[tokio::test(flavor = "multi_thread")] async fn test_selection_duplication() -> anyhow::Result<()> { diff --git a/helix-term/tests/test/commands/write.rs b/helix-term/tests/test/commands/write.rs new file mode 100644 index 00000000..0ea66a12 --- /dev/null +++ b/helix-term/tests/test/commands/write.rs @@ -0,0 +1,409 @@ +use std::{ + io::{Read, Seek, Write}, + ops::RangeInclusive, +}; + +use helix_core::diagnostic::Severity; +use helix_view::doc; + +use super::*; + +#[tokio::test(flavor = "multi_thread")] +async fn test_write_quit_fail() -> anyhow::Result<()> { + let file = helpers::new_readonly_tempfile()?; + let mut app = helpers::AppBuilder::new() + .with_file(file.path(), None) + .build()?; + + test_key_sequence( + &mut app, + Some("ihello:wq"), + Some(&|app| { + let mut docs: Vec<_> = app.editor.documents().collect(); + assert_eq!(1, docs.len()); + + let doc = docs.pop().unwrap(); + assert_eq!(Some(file.path()), doc.path().map(PathBuf::as_path)); + assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); + }), + false, + ) + .await?; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_buffer_close_concurrent() -> anyhow::Result<()> { + test_key_sequences( + &mut helpers::AppBuilder::new().build()?, + vec![ + ( + None, + Some(&|app| { + assert_eq!(1, app.editor.documents().count()); + assert!(!app.editor.is_err()); + }), + ), + ( + Some("ihello:new"), + Some(&|app| { + assert_eq!(2, app.editor.documents().count()); + assert!(!app.editor.is_err()); + }), + ), + ( + Some(":bufferclose"), + Some(&|app| { + assert_eq!(1, app.editor.documents().count()); + assert!(!app.editor.is_err()); + }), + ), + ], + false, + ) + .await?; + + // verify if writes are queued up, it finishes them before closing the buffer + let mut file = tempfile::NamedTempFile::new()?; + let mut command = String::new(); + const RANGE: RangeInclusive = 1..=1000; + + for i in RANGE { + let cmd = format!("%c{}:w!", i); + command.push_str(&cmd); + } + + command.push_str(":bufferclose"); + + let mut app = helpers::AppBuilder::new() + .with_file(file.path(), None) + .build()?; + + test_key_sequence( + &mut app, + Some(&command), + Some(&|app| { + assert!(!app.editor.is_err(), "error: {:?}", app.editor.get_status()); + + let doc = app.editor.document_by_path(file.path()); + assert!(doc.is_none(), "found doc: {:?}", doc); + }), + false, + ) + .await?; + + helpers::assert_file_has_content(file.as_file_mut(), &RANGE.end().to_string())?; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_write() -> anyhow::Result<()> { + let mut file = tempfile::NamedTempFile::new()?; + let mut app = helpers::AppBuilder::new() + .with_file(file.path(), None) + .build()?; + + test_key_sequence( + &mut app, + Some("ithe gostak distims the doshes:w"), + None, + false, + ) + .await?; + + file.as_file_mut().flush()?; + file.as_file_mut().sync_all()?; + + let mut file_content = String::new(); + file.as_file_mut().read_to_string(&mut file_content)?; + + assert_eq!( + helpers::platform_line("the gostak distims the doshes"), + file_content + ); + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_overwrite_protection() -> anyhow::Result<()> { + let mut file = tempfile::NamedTempFile::new()?; + let mut app = helpers::AppBuilder::new() + .with_file(file.path(), None) + .build()?; + + helpers::run_event_loop_until_idle(&mut app).await; + + file.as_file_mut() + .write_all(helpers::platform_line("extremely important content").as_bytes())?; + + file.as_file_mut().flush()?; + file.as_file_mut().sync_all()?; + + test_key_sequence(&mut app, Some(":x"), None, false).await?; + + file.as_file_mut().flush()?; + file.as_file_mut().sync_all()?; + + file.rewind()?; + let mut file_content = String::new(); + file.as_file_mut().read_to_string(&mut file_content)?; + + assert_eq!( + helpers::platform_line("extremely important content"), + file_content + ); + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_write_quit() -> anyhow::Result<()> { + let mut file = tempfile::NamedTempFile::new()?; + let mut app = helpers::AppBuilder::new() + .with_file(file.path(), None) + .build()?; + + test_key_sequence( + &mut app, + Some("ithe gostak distims the doshes:wq"), + None, + true, + ) + .await?; + + file.as_file_mut().flush()?; + file.as_file_mut().sync_all()?; + + let mut file_content = String::new(); + file.as_file_mut().read_to_string(&mut file_content)?; + + assert_eq!( + helpers::platform_line("the gostak distims the doshes"), + file_content + ); + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_write_concurrent() -> anyhow::Result<()> { + let mut file = tempfile::NamedTempFile::new()?; + let mut command = String::new(); + const RANGE: RangeInclusive = 1..=1000; + let mut app = helpers::AppBuilder::new() + .with_file(file.path(), None) + .build()?; + + for i in RANGE { + let cmd = format!("%c{}:w!", i); + command.push_str(&cmd); + } + + test_key_sequence(&mut app, Some(&command), None, false).await?; + + file.as_file_mut().flush()?; + file.as_file_mut().sync_all()?; + + let mut file_content = String::new(); + file.as_file_mut().read_to_string(&mut file_content)?; + assert_eq!(RANGE.end().to_string(), file_content); + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_write_fail_mod_flag() -> anyhow::Result<()> { + let file = helpers::new_readonly_tempfile()?; + let mut app = helpers::AppBuilder::new() + .with_file(file.path(), None) + .build()?; + + test_key_sequences( + &mut app, + vec![ + ( + None, + Some(&|app| { + let doc = doc!(app.editor); + assert!(!doc.is_modified()); + }), + ), + ( + Some("ihello"), + Some(&|app| { + let doc = doc!(app.editor); + assert!(doc.is_modified()); + }), + ), + ( + Some(":w"), + Some(&|app| { + assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); + + let doc = doc!(app.editor); + assert!(doc.is_modified()); + }), + ), + ], + false, + ) + .await?; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_write_scratch_to_new_path() -> anyhow::Result<()> { + let mut file = tempfile::NamedTempFile::new()?; + + test_key_sequence( + &mut AppBuilder::new().build()?, + Some(format!("ihello:w {}", file.path().to_string_lossy()).as_ref()), + Some(&|app| { + assert!(!app.editor.is_err()); + + let mut docs: Vec<_> = app.editor.documents().collect(); + assert_eq!(1, docs.len()); + + let doc = docs.pop().unwrap(); + assert_eq!(Some(&file.path().to_path_buf()), doc.path()); + }), + false, + ) + .await?; + + helpers::assert_file_has_content(file.as_file_mut(), &helpers::platform_line("hello"))?; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_write_scratch_no_path_fails() -> anyhow::Result<()> { + helpers::test_key_sequence_with_input_text( + None, + ("#[\n|]#", "ihello:w", "hello#[\n|]#"), + &|app| { + assert!(app.editor.is_err()); + + let mut docs: Vec<_> = app.editor.documents().collect(); + assert_eq!(1, docs.len()); + + let doc = docs.pop().unwrap(); + assert_eq!(None, doc.path()); + }, + false, + ) + .await?; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_write_auto_format_fails_still_writes() -> anyhow::Result<()> { + let mut file = tempfile::Builder::new().suffix(".rs").tempfile()?; + + let lang_conf = indoc! {r#" + [[language]] + name = "rust" + formatter = { command = "bash", args = [ "-c", "exit 1" ] } + "#}; + + let mut app = helpers::AppBuilder::new() + .with_file(file.path(), None) + .with_input_text("#[l|]#et foo = 0;\n") + .with_lang_config(helpers::test_syntax_conf(Some(lang_conf.into()))) + .build()?; + + test_key_sequences(&mut app, vec![(Some(":w"), None)], false).await?; + + // file still saves + helpers::assert_file_has_content(file.as_file_mut(), "let foo = 0;\n")?; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_write_new_path() -> anyhow::Result<()> { + let mut file1 = tempfile::NamedTempFile::new().unwrap(); + let mut file2 = tempfile::NamedTempFile::new().unwrap(); + let mut app = helpers::AppBuilder::new() + .with_file(file1.path(), None) + .build()?; + + test_key_sequences( + &mut app, + vec![ + ( + Some("ii can eat glass, it will not hurt me:w"), + Some(&|app| { + let doc = doc!(app.editor); + assert!(!app.editor.is_err()); + assert_eq!(file1.path(), doc.path().unwrap()); + }), + ), + ( + Some(&format!(":w {}", file2.path().to_string_lossy())), + Some(&|app| { + let doc = doc!(app.editor); + assert!(!app.editor.is_err()); + assert_eq!(file2.path(), doc.path().unwrap()); + assert!(app.editor.document_by_path(file1.path()).is_none()); + }), + ), + ], + false, + ) + .await?; + + helpers::assert_file_has_content( + file1.as_file_mut(), + &helpers::platform_line("i can eat glass, it will not hurt me\n"), + )?; + + helpers::assert_file_has_content( + file2.as_file_mut(), + &helpers::platform_line("i can eat glass, it will not hurt me\n"), + )?; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_write_fail_new_path() -> anyhow::Result<()> { + let file = helpers::new_readonly_tempfile()?; + + test_key_sequences( + &mut AppBuilder::new().build()?, + vec![ + ( + None, + Some(&|app| { + let doc = doc!(app.editor); + assert_ne!( + Some(&Severity::Error), + app.editor.get_status().map(|status| status.1) + ); + assert_eq!(None, doc.path()); + }), + ), + ( + Some(&format!(":w {}", file.path().to_string_lossy())), + Some(&|app| { + let doc = doc!(app.editor); + assert_eq!( + Some(&Severity::Error), + app.editor.get_status().map(|status| status.1) + ); + assert_eq!(None, doc.path()); + }), + ), + ], + false, + ) + .await?; + + Ok(()) +} diff --git a/helix-term/tests/test/write.rs b/helix-term/tests/test/write.rs deleted file mode 100644 index 81459b2f..00000000 --- a/helix-term/tests/test/write.rs +++ /dev/null @@ -1,319 +0,0 @@ -use std::{ - io::{Read, Seek, SeekFrom, Write}, - ops::RangeInclusive, -}; - -use helix_core::diagnostic::Severity; -use helix_view::doc; - -use super::*; - -#[tokio::test(flavor = "multi_thread")] -async fn test_write() -> anyhow::Result<()> { - let mut file = tempfile::NamedTempFile::new()?; - let mut app = helpers::AppBuilder::new() - .with_file(file.path(), None) - .build()?; - - test_key_sequence( - &mut app, - Some("ithe gostak distims the doshes:w"), - None, - false, - ) - .await?; - - file.as_file_mut().flush()?; - file.as_file_mut().sync_all()?; - - let mut file_content = String::new(); - file.as_file_mut().read_to_string(&mut file_content)?; - - assert_eq!( - helpers::platform_line("the gostak distims the doshes"), - file_content - ); - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_overwrite_protection() -> anyhow::Result<()> { - let mut file = tempfile::NamedTempFile::new()?; - let mut app = helpers::AppBuilder::new() - .with_file(file.path(), None) - .build()?; - - helpers::run_event_loop_until_idle(&mut app).await; - - file.as_file_mut() - .write_all(helpers::platform_line("extremely important content").as_bytes())?; - - file.as_file_mut().flush()?; - file.as_file_mut().sync_all()?; - - test_key_sequence(&mut app, Some(":x"), None, false).await?; - - file.as_file_mut().flush()?; - file.as_file_mut().sync_all()?; - - file.seek(SeekFrom::Start(0))?; - let mut file_content = String::new(); - file.as_file_mut().read_to_string(&mut file_content)?; - - assert_eq!( - helpers::platform_line("extremely important content"), - file_content - ); - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_write_quit() -> anyhow::Result<()> { - let mut file = tempfile::NamedTempFile::new()?; - let mut app = helpers::AppBuilder::new() - .with_file(file.path(), None) - .build()?; - - test_key_sequence( - &mut app, - Some("ithe gostak distims the doshes:wq"), - None, - true, - ) - .await?; - - file.as_file_mut().flush()?; - file.as_file_mut().sync_all()?; - - let mut file_content = String::new(); - file.as_file_mut().read_to_string(&mut file_content)?; - - assert_eq!( - helpers::platform_line("the gostak distims the doshes"), - file_content - ); - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_write_concurrent() -> anyhow::Result<()> { - let mut file = tempfile::NamedTempFile::new()?; - let mut command = String::new(); - const RANGE: RangeInclusive = 1..=1000; - let mut app = helpers::AppBuilder::new() - .with_file(file.path(), None) - .build()?; - - for i in RANGE { - let cmd = format!("%c{}:w!", i); - command.push_str(&cmd); - } - - test_key_sequence(&mut app, Some(&command), None, false).await?; - - file.as_file_mut().flush()?; - file.as_file_mut().sync_all()?; - - let mut file_content = String::new(); - file.as_file_mut().read_to_string(&mut file_content)?; - assert_eq!(RANGE.end().to_string(), file_content); - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_write_fail_mod_flag() -> anyhow::Result<()> { - let file = helpers::new_readonly_tempfile()?; - let mut app = helpers::AppBuilder::new() - .with_file(file.path(), None) - .build()?; - - test_key_sequences( - &mut app, - vec![ - ( - None, - Some(&|app| { - let doc = doc!(app.editor); - assert!(!doc.is_modified()); - }), - ), - ( - Some("ihello"), - Some(&|app| { - let doc = doc!(app.editor); - assert!(doc.is_modified()); - }), - ), - ( - Some(":w"), - Some(&|app| { - assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1); - - let doc = doc!(app.editor); - assert!(doc.is_modified()); - }), - ), - ], - false, - ) - .await?; - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_write_scratch_to_new_path() -> anyhow::Result<()> { - let mut file = tempfile::NamedTempFile::new()?; - - test_key_sequence( - &mut AppBuilder::new().build()?, - Some(format!("ihello:w {}", file.path().to_string_lossy()).as_ref()), - Some(&|app| { - assert!(!app.editor.is_err()); - - let mut docs: Vec<_> = app.editor.documents().collect(); - assert_eq!(1, docs.len()); - - let doc = docs.pop().unwrap(); - assert_eq!(Some(&file.path().to_path_buf()), doc.path()); - }), - false, - ) - .await?; - - helpers::assert_file_has_content(file.as_file_mut(), &helpers::platform_line("hello"))?; - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_write_scratch_no_path_fails() -> anyhow::Result<()> { - helpers::test_key_sequence_with_input_text( - None, - ("#[\n|]#", "ihello:w", "hello#[\n|]#"), - &|app| { - assert!(app.editor.is_err()); - - let mut docs: Vec<_> = app.editor.documents().collect(); - assert_eq!(1, docs.len()); - - let doc = docs.pop().unwrap(); - assert_eq!(None, doc.path()); - }, - false, - ) - .await?; - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_write_auto_format_fails_still_writes() -> anyhow::Result<()> { - let mut file = tempfile::Builder::new().suffix(".rs").tempfile()?; - - let lang_conf = indoc! {r#" - [[language]] - name = "rust" - formatter = { command = "bash", args = [ "-c", "exit 1" ] } - "#}; - - let mut app = helpers::AppBuilder::new() - .with_file(file.path(), None) - .with_input_text("#[l|]#et foo = 0;\n") - .with_lang_config(helpers::test_syntax_conf(Some(lang_conf.into()))) - .build()?; - - test_key_sequences(&mut app, vec![(Some(":w"), None)], false).await?; - - // file still saves - helpers::assert_file_has_content(file.as_file_mut(), "let foo = 0;\n")?; - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_write_new_path() -> anyhow::Result<()> { - let mut file1 = tempfile::NamedTempFile::new().unwrap(); - let mut file2 = tempfile::NamedTempFile::new().unwrap(); - let mut app = helpers::AppBuilder::new() - .with_file(file1.path(), None) - .build()?; - - test_key_sequences( - &mut app, - vec![ - ( - Some("ii can eat glass, it will not hurt me:w"), - Some(&|app| { - let doc = doc!(app.editor); - assert!(!app.editor.is_err()); - assert_eq!(file1.path(), doc.path().unwrap()); - }), - ), - ( - Some(&format!(":w {}", file2.path().to_string_lossy())), - Some(&|app| { - let doc = doc!(app.editor); - assert!(!app.editor.is_err()); - assert_eq!(file2.path(), doc.path().unwrap()); - assert!(app.editor.document_by_path(file1.path()).is_none()); - }), - ), - ], - false, - ) - .await?; - - helpers::assert_file_has_content( - file1.as_file_mut(), - &helpers::platform_line("i can eat glass, it will not hurt me\n"), - )?; - - helpers::assert_file_has_content( - file2.as_file_mut(), - &helpers::platform_line("i can eat glass, it will not hurt me\n"), - )?; - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_write_fail_new_path() -> anyhow::Result<()> { - let file = helpers::new_readonly_tempfile()?; - - test_key_sequences( - &mut AppBuilder::new().build()?, - vec![ - ( - None, - Some(&|app| { - let doc = doc!(app.editor); - assert_ne!( - Some(&Severity::Error), - app.editor.get_status().map(|status| status.1) - ); - assert_eq!(None, doc.path()); - }), - ), - ( - Some(&format!(":w {}", file.path().to_string_lossy())), - Some(&|app| { - let doc = doc!(app.editor); - assert_eq!( - Some(&Severity::Error), - app.editor.get_status().map(|status| status.1) - ); - assert_eq!(None, doc.path()); - }), - ), - ], - false, - ) - .await?; - - Ok(()) -} -- cgit v1.2.3-70-g09d2