laburnum 1.17.3

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.
// Copyright Two Neutron Stars Incorporated and contributors
// SPDX-License-Identifier: BlueOak-1.0.0

use {
  super::storage::{TestPartition, Test1Partition, TestPartitions, TestSortKey},
  crate::{
    ContentHash, Ident, Uri,
    database::{
      PartitionKey,
      chunk::RecordWriter,
      partitions::HasPartition,
      storage::Partitions,
    },
  },
};

fn test_uri(path: &str) -> Uri {
  Uri::parse(path).expect("valid test URI")
}

#[test]
fn partition_store_span_index_round_trip() {
  let stores = TestPartitions::new_stores();
  let store = <
    <TestPartitions as Partitions>::Stores as HasPartition<TestPartition>
  >::store(&stores);

  let uri = test_uri("file:///test.gold");
  let hash_a = ContentHash::new(&[1, 0, 0, 0]);
  let hash_b = ContentHash::new(&[2, 0, 0, 0]);

  store.span_index_apply(
    &[],
    vec![
      ("a".to_string(), uri.clone(), 0, 10, hash_a),
      ("b".to_string(), uri.clone(), 20, 5, hash_b),
    ],
  );

  assert_eq!(store.span_index_query(&uri, 5), Some(hash_a));
  assert_eq!(store.span_index_query(&uri, 22), Some(hash_b));
  assert_eq!(store.span_index_query(&uri, 15), None);

  let other_uri = test_uri("file:///other.gold");
  assert_eq!(store.span_index_query(&other_uri, 5), None);
}

#[test]
fn partition_store_span_index_reapply_same_key_overwrites() {
  let stores = TestPartitions::new_stores();
  let store = <
    <TestPartitions as Partitions>::Stores as HasPartition<TestPartition>
  >::store(&stores);

  let uri = test_uri("file:///test.gold");
  let hash_old = ContentHash::new(&[1, 0, 0, 0]);
  let hash_new = ContentHash::new(&[2, 0, 0, 0]);

  store.span_index_apply(&[], vec![("k".to_string(), uri.clone(), 0, 10, hash_old)]);
  assert_eq!(store.span_index_query(&uri, 5), Some(hash_old));

  // Re-apply the SAME sort_key with a new span: overwrites just that entry.
  store.span_index_apply(&[], vec![("k".to_string(), uri.clone(), 0, 10, hash_new)]);
  assert_eq!(store.span_index_query(&uri, 5), Some(hash_new));
}

#[test]
fn partition_store_span_index_merge_keeps_prior_entries() {
  // The core fix: two applies for the SAME uri with DIFFERENT sort_keys both
  // remain queryable. The old replace would have lost the first.
  let stores = TestPartitions::new_stores();
  let store = <
    <TestPartitions as Partitions>::Stores as HasPartition<TestPartition>
  >::store(&stores);

  let uri = test_uri("file:///test.gold");
  let hash_a = ContentHash::new(&[1, 0, 0, 0]);
  let hash_b = ContentHash::new(&[2, 0, 0, 0]);

  store.span_index_apply(&[], vec![("a".to_string(), uri.clone(), 0, 10, hash_a)]);
  store.span_index_apply(&[], vec![("b".to_string(), uri.clone(), 20, 5, hash_b)]);

  assert_eq!(store.span_index_query(&uri, 5), Some(hash_a));
  assert_eq!(store.span_index_query(&uri, 22), Some(hash_b));
}

#[test]
fn partition_store_span_index_removed_key_drops_only_that_entry() {
  let stores = TestPartitions::new_stores();
  let store = <
    <TestPartitions as Partitions>::Stores as HasPartition<TestPartition>
  >::store(&stores);

  let uri = test_uri("file:///test.gold");
  let hash_a = ContentHash::new(&[1, 0, 0, 0]);
  let hash_b = ContentHash::new(&[2, 0, 0, 0]);

  store.span_index_apply(
    &[],
    vec![
      ("a".to_string(), uri.clone(), 0, 10, hash_a),
      ("b".to_string(), uri.clone(), 20, 5, hash_b),
    ],
  );

  // Removing "a" drops that entry but leaves "b".
  store.span_index_apply(&["a".to_string()], vec![]);
  assert_eq!(store.span_index_query(&uri, 5), None);
  assert_eq!(store.span_index_query(&uri, 22), Some(hash_b));
}

#[test]
fn partition_store_span_index_remove() {
  let stores = TestPartitions::new_stores();
  let store = <
    <TestPartitions as Partitions>::Stores as HasPartition<TestPartition>
  >::store(&stores);

  let uri = test_uri("file:///test.gold");
  let hash = ContentHash::new(&[1, 0, 0, 0]);

  store.span_index_apply(&[], vec![("k".to_string(), uri.clone(), 0, 10, hash)]);
  assert_eq!(store.span_index_query(&uri, 5), Some(hash));

  store.span_index_remove(&uri);
  assert_eq!(store.span_index_query(&uri, 5), None);

  // Re-applying the same key after a full URI remove starts fresh.
  store.span_index_apply(&[], vec![("k".to_string(), uri.clone(), 0, 10, hash)]);
  assert_eq!(store.span_index_query(&uri, 5), Some(hash));
}

#[test]
fn record_writer_index_span_stages_per_partition() {
  let mut writer = RecordWriter::<TestPartitions>::new(Ident::new("task"));

  let mut span_cache = crate::SpanCache::for_test(3, 0);
  let span1 = span_cache.create_span(0, 10);
  let span2 = span_cache.create_span(20, 5);
  let span3 = span_cache.create_span(30, 5);
  let hash1 = ContentHash::new(&[1, 0, 0, 0]);
  let hash2 = ContentHash::new(&[2, 0, 0, 0]);
  let hash3 = ContentHash::new(&[3, 0, 0, 0]);

  writer.index_span::<TestPartition>("a".to_string(), span1, hash1);
  writer.index_span::<TestPartition>("b".to_string(), span2, hash2);
  writer.index_span::<Test1Partition>("c".to_string(), span3, hash3);

  let chunk = writer.build();

  let test_intervals = chunk.staged_intervals().get(&TestPartition::KEY);
  assert!(test_intervals.is_some());
  assert_eq!(test_intervals.map(|v| v.len()), Some(2));

  let test1_intervals = chunk.staged_intervals().get(&Test1Partition::KEY);
  assert!(test1_intervals.is_some());
  assert_eq!(test1_intervals.map(|v| v.len()), Some(1));
}

#[test]
fn partitions_trait_span_index_dispatch() {
  let stores = TestPartitions::new_stores();
  let uri = test_uri("file:///dispatch.gold");
  let hash = ContentHash::new(&[42, 0, 0, 0]);

  TestPartitions::span_index_apply(
    &stores,
    TestPartition::KEY,
    &[],
    vec![(TestSortKey::Test("k".to_string()), uri.clone(), 0, 10, hash)],
  );

  let store = <
    <TestPartitions as Partitions>::Stores as HasPartition<TestPartition>
  >::store(&stores);
  assert_eq!(store.span_index_query(&uri, 5), Some(hash));

  TestPartitions::span_index_remove(&stores, TestPartition::KEY, &uri);
  assert_eq!(store.span_index_query(&uri, 5), None);
}