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

/// Creates a virtual filesystem for testing purposes.
///
/// # Panics
/// This macro is intended for test use only and will panic if:
/// - The base path cannot be parsed as a valid URI
/// - A file path cannot be joined to the base
/// - Writing a file fails
#[cfg(any(test, feature = "test"))]
#[macro_export]
macro_rules! virtual_fs {
  ($base_path:literal, { $($file:literal => $content:expr),* $(,)? }) => {{
    let fs = $crate::fs::MemoryFileSystem::new();
    let base_path = format!("file://{}/", $base_path);
    let base = match $crate::Uri::parse(&base_path) {
      Ok(uri) => uri,
      Err(e) => panic!("virtual_fs!: invalid base path '{}': {:?}", $base_path, e),
    };
    $(
      let file_uri = match base.join($file) {
        Some(uri) => uri,
        None => panic!("virtual_fs!: invalid file path '{}'", $file),
      };
      if let Err(e) = fs.write_str(&file_uri, $content) {
        panic!("virtual_fs!: failed to write file '{}': {:?}", $file, e);
      }
    )*
    (fs, base)
  }};
}

#[cfg(any(test, feature = "test"))]
#[macro_export]
macro_rules! filesystem_test {
  ($name:ident,
    files: { $dir:literal: { $($content:tt)* }$(,)? },
    glob { $($pattern:literal: [$($expected:literal),*]),* $(,)? }$(,)?
  ) => {
    paste::paste! {
      #[test]
      fn [<test_physical_ $name>]() {
        let mut test_data = $crate::fs::tests::TestData::new();
        test_data.dir($dir, |d| {
            $crate::build_testing_fs!(d, $($content)*);
        });
        $(
            test_data.add_glob_test($pattern, vec![$($expected.to_string()),*]);
        )*
        let (temp_dir, base_uri) = test_data.create_physical();
        let fs = $crate::fs::PhysicalFileSystem::new(base_uri.clone()).unwrap();
        $crate::fs::tests::run_filesystem_test(fs, test_data, base_uri);

        temp_dir.close().unwrap();
      }

      #[test]
      fn [<test_memory_ $name>]() {
        let mut test_data = $crate::fs::tests::TestData::new();
        test_data.dir($dir, |d| {
            $crate::build_testing_fs!(d, $($content)*);
        });
        $(
            test_data.add_glob_test($pattern, vec![$($expected.to_string()),*]);
        )*
        let fs = $crate::fs::MemoryFileSystem::new();
        let base_uri = $crate::Uri::parse("memory:///").unwrap();
        $crate::fs::tests::run_filesystem_test(fs, test_data, base_uri);
      }
    }
  };
}

#[cfg(any(test, feature = "test"))]
#[macro_export]
macro_rules! build_testing_fs {
    // Handle empty case
    ($builder:expr, ) => {};

    // Handle file with trailing comma
    ($builder:expr, $name:literal: $content:literal, $($rest:tt)*) => {
        $builder.file($name, $content);
        $crate::build_fs!($builder, $($rest)*);
    };

    // Handle directory with trailing comma
    ($builder:expr, $name:literal: { $($content:tt)* }, $($rest:tt)*) => {
        $builder.dir($name, |d| {
            $crate::build_fs!(d, $($content)*);
        });
        $crate::build_fs!($builder, $($rest)*);
    };

    // Handle file as last item
    ($builder:expr, $name:literal: $content:literal) => {
        $builder.file($name, $content);
    };

    // Handle directory as last item
    ($builder:expr, $name:literal: { $($content:tt)* }) => {
        $builder.dir($name, |d| {
            $crate::build_fs!(d, $($content)*);
        });
    };
}