laburnum 1.17.0

An LSP framework for building language servers and compilers, powered by an incremental query tree with content-addressed storage, task-based dataflow, and parallel queries.
Documentation
// Copyright Two Neutron Stars Incorporated and contributors
// SPDX-License-Identifier: BlueOak-1.0.0

use {
  laburnum::{
    Laburnum,
    protocol::lsp::{
        InitializeParams,
        InitializeResult,
      },
  },
  macro_rules_attribute::apply,
  smol_macros::test,
};

mod common;
use common::TestPartitions;

#[apply(test!)]
#[test_log::test]
async fn test_successful_initialization() {
  let (server, client) = Laburnum::<TestPartitions, _>::example().build_test();
  let mut snapshot = ferrotype::Ferrotype::new();

  let result = client.initialize(InitializeParams::default()).await;

  assert!(
    result.is_ok(),
    "Initialize should return a result: {:?}",
    result
  );

  let init_result: InitializeResult = result.unwrap();

  assert!(
    init_result.capabilities.text_document_sync.is_some(),
    "Server should support text document sync"
  );

  client.initialized().await.unwrap();

  let stop_result = client.stop_test(&mut snapshot).await;
  assert!(stop_result.is_ok());

  server.close().expect("Failed to close server");

  ferrotype::assert!(snapshot);
}

#[apply(test!)]
#[test_log::test]
async fn test_request_before_initialization() {
  let (server, client) = Laburnum::<TestPartitions, _>::example().build_test();
  let mut snapshot = ferrotype::Ferrotype::new();

  let hover_result = client
    .hover_request(laburnum::protocol::lsp::HoverParams {
      text_document_position_params:
        laburnum::protocol::lsp::TextDocumentPositionParams {
          text_document: laburnum::protocol::lsp::TextDocumentIdentifier {
            uri: "file:///test.txt".parse().unwrap(),
          },
          position:      laburnum::protocol::lsp::Position {
            line:      0,
            character: 0,
          },
        },
      work_done_progress_params:     Default::default(),
    })
    .await;

  assert!(
    hover_result.is_err(),
    "Request before init should return error"
  );
  let error = hover_result.unwrap_err();
  assert!(
    matches!(
      error,
      laburnum::connect::lsp::errors::LspClientError::NotInitialized
    ),
    "Expected NotInitialized error, got: {:?}",
    error
  );

  client.start(InitializeParams::default()).await.ok();
  client.stop_test(&mut snapshot).await.ok();

  server.close().expect("Failed to close server");

  ferrotype::assert!(snapshot);
}

#[apply(test!)]
#[test_log::test]
async fn test_multiple_initialize_requests() {
  let (server, client) = Laburnum::<TestPartitions, _>::example().build_test();
  let mut snapshot = ferrotype::Ferrotype::new();

  let first_result = client.initialize(InitializeParams::default()).await;
  assert!(first_result.is_ok(), "First initialize should succeed");

  client.initialized().await.unwrap();

  let second_result = client.initialize(InitializeParams::default()).await;

  assert!(
    second_result.is_err(),
    "Second initialize should return error"
  );

  client.stop_test(&mut snapshot).await.ok();

  server.close().expect("Failed to close server");

  ferrotype::assert!(snapshot);
}

#[apply(test!)]
#[test_log::test]
async fn test_shutdown_before_initialization() {
  let (server, client) = Laburnum::<TestPartitions, _>::example().build_test();
  let mut snapshot = ferrotype::Ferrotype::new();

  let shutdown_result = client.shutdown().await;

  assert!(
    shutdown_result.is_err(),
    "Shutdown before init should return error"
  );

  client.start(InitializeParams::default()).await.ok();
  client.stop_test(&mut snapshot).await.ok();

  server.close().expect("Failed to close server");

  ferrotype::assert!(snapshot);
}

#[apply(test!)]
#[test_log::test]
async fn test_exit_after_initialization_without_shutdown() {
  let (server, client) = Laburnum::<TestPartitions, _>::example().build_test();
  let mut snapshot = ferrotype::Ferrotype::new();

  client.start(InitializeParams::default()).await.ok();

  client.stop_test(&mut snapshot).await.ok();

  server.close().expect("Failed to close server");

  ferrotype::assert!(snapshot);
}

#[apply(test!)]
#[test_log::test]
async fn test_normal_request_after_initialization() {
  let (server, client) = Laburnum::<TestPartitions, _>::example().build_test();
  let mut snapshot = ferrotype::Ferrotype::new();

  client.start(InitializeParams::default()).await.ok();

  let _hover_result = client
    .hover_request(laburnum::protocol::lsp::HoverParams {
      text_document_position_params:
        laburnum::protocol::lsp::TextDocumentPositionParams {
          text_document: laburnum::protocol::lsp::TextDocumentIdentifier {
            uri: "file:///test.txt".parse().unwrap(),
          },
          position:      laburnum::protocol::lsp::Position {
            line:      0,
            character: 0,
          },
        },
      work_done_progress_params:     Default::default(),
    })
    .await;

  client.stop_test(&mut snapshot).await.ok();

  server.close().expect("Failed to close server");

  ferrotype::assert!(snapshot);
}