Add more tests

Kirill Bulatov created

Change summary

crates/collab/src/tests/integration_tests.rs | 138 +++++++++++++++++++++
crates/editor/src/editor_tests.rs            |  33 ++++
2 files changed, 162 insertions(+), 9 deletions(-)

Detailed changes

crates/collab/src/tests/integration_tests.rs 🔗

@@ -15,12 +15,14 @@ use gpui::{executor::Deterministic, test::EmptyView, AppContext, ModelHandle, Te
 use indoc::indoc;
 use language::{
     language_settings::{AllLanguageSettings, Formatter, InlayHintSettings},
-    tree_sitter_rust, Anchor, Diagnostic, DiagnosticEntry, FakeLspAdapter, Language,
-    LanguageConfig, LineEnding, OffsetRangeExt, Point, Rope,
+    tree_sitter_rust, Anchor, BundledFormatter, Diagnostic, DiagnosticEntry, FakeLspAdapter,
+    Language, LanguageConfig, LineEnding, OffsetRangeExt, Point, Rope,
 };
 use live_kit_client::MacOSDisplay;
 use lsp::LanguageServerId;
-use project::{search::SearchQuery, DiagnosticSummary, HoverBlockKind, Project, ProjectPath};
+use project::{
+    search::SearchQuery, DiagnosticSummary, FormatTrigger, HoverBlockKind, Project, ProjectPath,
+};
 use rand::prelude::*;
 use serde_json::json;
 use settings::SettingsStore;
@@ -4407,8 +4409,6 @@ async fn test_formatting_buffer(
     cx_a: &mut TestAppContext,
     cx_b: &mut TestAppContext,
 ) {
-    use project::FormatTrigger;
-
     let mut server = TestServer::start(&deterministic).await;
     let client_a = server.create_client(cx_a, "user_a").await;
     let client_b = server.create_client(cx_b, "user_b").await;
@@ -4511,6 +4511,134 @@ async fn test_formatting_buffer(
     );
 }
 
+#[gpui::test(iterations = 10)]
+async fn test_prettier_formatting_buffer(
+    deterministic: Arc<Deterministic>,
+    cx_a: &mut TestAppContext,
+    cx_b: &mut TestAppContext,
+) {
+    let mut server = TestServer::start(&deterministic).await;
+    let client_a = server.create_client(cx_a, "user_a").await;
+    let client_b = server.create_client(cx_b, "user_b").await;
+    server
+        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
+        .await;
+    let active_call_a = cx_a.read(ActiveCall::global);
+
+    // Set up a fake language server.
+    let mut language = Language::new(
+        LanguageConfig {
+            name: "Rust".into(),
+            path_suffixes: vec!["rs".to_string()],
+            ..Default::default()
+        },
+        Some(tree_sitter_rust::language()),
+    );
+    let test_plugin = "test_plugin";
+    let mut fake_language_servers = language
+        .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+            enabled_formatters: vec![BundledFormatter::Prettier {
+                parser_name: Some("test_parser"),
+                plugin_names: vec![test_plugin],
+            }],
+            ..Default::default()
+        }))
+        .await;
+    let language = Arc::new(language);
+    client_a.language_registry().add(Arc::clone(&language));
+
+    // Here we insert a fake tree with a directory that exists on disk. This is needed
+    // because later we'll invoke a command, which requires passing a working directory
+    // that points to a valid location on disk.
+    let directory = env::current_dir().unwrap();
+    let buffer_text = "let one = \"two\"";
+    client_a
+        .fs()
+        .insert_tree(&directory, json!({ "a.rs": buffer_text }))
+        .await;
+    let (project_a, worktree_id) = client_a.build_local_project(&directory, cx_a).await;
+    let prettier_format_suffix = project_a.update(cx_a, |project, _| {
+        let suffix = project.enable_test_prettier(&[test_plugin]);
+        project.languages().add(language);
+        suffix
+    });
+    let buffer_a = cx_a
+        .background()
+        .spawn(project_a.update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
+        .await
+        .unwrap();
+
+    let project_id = active_call_a
+        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+        .await
+        .unwrap();
+    let project_b = client_b.build_remote_project(project_id, cx_b).await;
+    let buffer_b = cx_b
+        .background()
+        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
+        .await
+        .unwrap();
+
+    cx_a.update(|cx| {
+        cx.update_global(|store: &mut SettingsStore, cx| {
+            store.update_user_settings::<AllLanguageSettings>(cx, |file| {
+                file.defaults.formatter = Some(Formatter::Auto);
+            });
+        });
+    });
+    cx_b.update(|cx| {
+        cx.update_global(|store: &mut SettingsStore, cx| {
+            store.update_user_settings::<AllLanguageSettings>(cx, |file| {
+                file.defaults.formatter = Some(Formatter::LanguageServer);
+            });
+        });
+    });
+    let fake_language_server = fake_language_servers.next().await.unwrap();
+    fake_language_server.handle_request::<lsp::request::Formatting, _, _>(|_, _| async move {
+        panic!(
+            "Unexpected: prettier should be preferred since it's enabled and language supports it"
+        )
+    });
+
+    project_b
+        .update(cx_b, |project, cx| {
+            project.format(
+                HashSet::from_iter([buffer_b.clone()]),
+                true,
+                FormatTrigger::Save,
+                cx,
+            )
+        })
+        .await
+        .unwrap();
+    cx_a.foreground().run_until_parked();
+    cx_b.foreground().run_until_parked();
+    assert_eq!(
+        buffer_b.read_with(cx_b, |buffer, _| buffer.text()),
+        buffer_text.to_string() + "\n" + prettier_format_suffix,
+        "Prettier formatting was not applied to client buffer after client's request"
+    );
+
+    project_a
+        .update(cx_a, |project, cx| {
+            project.format(
+                HashSet::from_iter([buffer_a.clone()]),
+                true,
+                FormatTrigger::Manual,
+                cx,
+            )
+        })
+        .await
+        .unwrap();
+    cx_a.foreground().run_until_parked();
+    cx_b.foreground().run_until_parked();
+    assert_eq!(
+        buffer_b.read_with(cx_b, |buffer, _| buffer.text()),
+        buffer_text.to_string() + "\n" + prettier_format_suffix + "\n" + prettier_format_suffix,
+        "Prettier formatting was not applied to client buffer after host's request"
+    );
+}
+
 #[gpui::test(iterations = 10)]
 async fn test_definition(
     deterministic: Arc<Deterministic>,

crates/editor/src/editor_tests.rs 🔗

@@ -5076,7 +5076,9 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) {
 
 #[gpui::test]
 async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) {
-    init_test(cx, |_| {});
+    init_test(cx, |settings| {
+        settings.defaults.formatter = Some(language_settings::Formatter::LanguageServer)
+    });
 
     let mut language = Language::new(
         LanguageConfig {
@@ -5092,6 +5094,12 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) {
                 document_formatting_provider: Some(lsp::OneOf::Left(true)),
                 ..Default::default()
             },
+            // Enable Prettier formatting for the same buffer, and ensure
+            // LSP is called instead of Prettier.
+            enabled_formatters: vec![BundledFormatter::Prettier {
+                parser_name: Some("test_parser"),
+                plugin_names: Vec::new(),
+            }],
             ..Default::default()
         }))
         .await;
@@ -5100,7 +5108,10 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) {
     fs.insert_file("/file.rs", Default::default()).await;
 
     let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
-    project.update(cx, |project, _| project.languages().add(Arc::new(language)));
+    project.update(cx, |project, _| {
+        project.enable_test_prettier(&[]);
+        project.languages().add(Arc::new(language));
+    });
     let buffer = project
         .update(cx, |project, cx| project.open_local_buffer("/file.rs", cx))
         .await
@@ -5218,7 +5229,9 @@ async fn test_concurrent_format_requests(cx: &mut gpui::TestAppContext) {
 
 #[gpui::test]
 async fn test_strip_whitespace_and_format_via_lsp(cx: &mut gpui::TestAppContext) {
-    init_test(cx, |_| {});
+    init_test(cx, |settings| {
+        settings.defaults.formatter = Some(language_settings::Formatter::Auto)
+    });
 
     let mut cx = EditorLspTestContext::new_rust(
         lsp::ServerCapabilities {
@@ -7864,12 +7877,24 @@ async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
         editor.perform_format(project.clone(), FormatTrigger::Manual, cx)
     });
     format.await.unwrap();
-
     assert_eq!(
         editor.read_with(cx, |editor, cx| editor.text(cx)),
         buffer_text.to_string() + prettier_format_suffix,
         "Test prettier formatting was not applied to the original buffer text",
     );
+
+    update_test_language_settings(cx, |settings| {
+        settings.defaults.formatter = Some(language_settings::Formatter::Auto)
+    });
+    let format = editor.update(cx, |editor, cx| {
+        editor.perform_format(project.clone(), FormatTrigger::Manual, cx)
+    });
+    format.await.unwrap();
+    assert_eq!(
+        editor.read_with(cx, |editor, cx| editor.text(cx)),
+        buffer_text.to_string() + prettier_format_suffix + "\n" + prettier_format_suffix,
+        "Autoformatting (via test prettier) was not applied to the original buffer text",
+    );
 }
 
 fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {