Add multi buffer test for tab map work
This commit is contained in:
parent
aa39f979b9
commit
42ce2238c0
2 changed files with 147 additions and 8 deletions
|
@ -7729,12 +7729,12 @@ impl<'a> Iterator for MultiBufferChunks<'a> {
|
||||||
// FIXME: We should be handling bitmap for tabs and chars here
|
// FIXME: We should be handling bitmap for tabs and chars here
|
||||||
// Because we do a split at operation the bitmaps will be off
|
// Because we do a split at operation the bitmaps will be off
|
||||||
Some(Chunk {
|
Some(Chunk {
|
||||||
text: before,
|
text: dbg!(before),
|
||||||
..chunk.clone()
|
..chunk.clone()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
self.range.start = chunk_end;
|
self.range.start = chunk_end;
|
||||||
self.buffer_chunk.take()
|
dbg!(self.buffer_chunk.take())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DiffTransform::DeletedHunk {
|
DiffTransform::DeletedHunk {
|
||||||
|
@ -7767,12 +7767,13 @@ impl<'a> Iterator for MultiBufferChunks<'a> {
|
||||||
let chunk = if let Some(chunk) = chunks.next() {
|
let chunk = if let Some(chunk) = chunks.next() {
|
||||||
self.range.start += chunk.text.len();
|
self.range.start += chunk.text.len();
|
||||||
self.diff_base_chunks = Some((*buffer_id, chunks));
|
self.diff_base_chunks = Some((*buffer_id, chunks));
|
||||||
chunk
|
dbg!(chunk)
|
||||||
} else {
|
} else {
|
||||||
debug_assert!(has_trailing_newline);
|
debug_assert!(has_trailing_newline);
|
||||||
self.range.start += "\n".len();
|
self.range.start += "\n".len();
|
||||||
Chunk {
|
Chunk {
|
||||||
text: "\n",
|
text: "\n",
|
||||||
|
chars: 1u128,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -7868,9 +7869,11 @@ impl<'a> Iterator for ExcerptChunks<'a> {
|
||||||
|
|
||||||
if self.footer_height > 0 {
|
if self.footer_height > 0 {
|
||||||
let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
|
let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) };
|
||||||
|
let chars = (1 << self.footer_height) - 1;
|
||||||
self.footer_height = 0;
|
self.footer_height = 0;
|
||||||
return Some(Chunk {
|
return Some(Chunk {
|
||||||
text,
|
text,
|
||||||
|
chars,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3721,7 +3721,6 @@ fn test_new_empty_buffers_title_can_be_set(cx: &mut App) {
|
||||||
|
|
||||||
#[gpui::test(iterations = 100)]
|
#[gpui::test(iterations = 100)]
|
||||||
fn test_random_chunk_bitmaps(cx: &mut App, mut rng: StdRng) {
|
fn test_random_chunk_bitmaps(cx: &mut App, mut rng: StdRng) {
|
||||||
// Generate random multibuffer using existing test infrastructure
|
|
||||||
let multibuffer = if rng.r#gen() {
|
let multibuffer = if rng.r#gen() {
|
||||||
let len = rng.gen_range(0..10000);
|
let len = rng.gen_range(0..10000);
|
||||||
let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
|
let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
|
||||||
|
@ -3733,7 +3732,6 @@ fn test_random_chunk_bitmaps(cx: &mut App, mut rng: StdRng) {
|
||||||
|
|
||||||
let snapshot = multibuffer.read(cx).snapshot(cx);
|
let snapshot = multibuffer.read(cx).snapshot(cx);
|
||||||
|
|
||||||
// Get all chunks and verify their bitmaps
|
|
||||||
let chunks = snapshot.chunks(0..snapshot.len(), false);
|
let chunks = snapshot.chunks(0..snapshot.len(), false);
|
||||||
|
|
||||||
for chunk in chunks {
|
for chunk in chunks {
|
||||||
|
@ -3741,7 +3739,6 @@ fn test_random_chunk_bitmaps(cx: &mut App, mut rng: StdRng) {
|
||||||
let chars_bitmap = chunk.chars;
|
let chars_bitmap = chunk.chars;
|
||||||
let tabs_bitmap = chunk.tabs;
|
let tabs_bitmap = chunk.tabs;
|
||||||
|
|
||||||
// Check empty chunks have empty bitmaps
|
|
||||||
if chunk_text.is_empty() {
|
if chunk_text.is_empty() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
chars_bitmap, 0,
|
chars_bitmap, 0,
|
||||||
|
@ -3751,7 +3748,6 @@ fn test_random_chunk_bitmaps(cx: &mut App, mut rng: StdRng) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that chunk text doesn't exceed 128 bytes
|
|
||||||
assert!(
|
assert!(
|
||||||
chunk_text.len() <= 128,
|
chunk_text.len() <= 128,
|
||||||
"Chunk text length {} exceeds 128 bytes",
|
"Chunk text length {} exceeds 128 bytes",
|
||||||
|
@ -3781,7 +3777,147 @@ fn test_random_chunk_bitmaps(cx: &mut App, mut rng: StdRng) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify tabs bitmap
|
for (byte_idx, byte) in chunk_text.bytes().enumerate() {
|
||||||
|
let is_tab = byte == b'\t';
|
||||||
|
let has_bit = tabs_bitmap & (1 << byte_idx) != 0;
|
||||||
|
|
||||||
|
if has_bit != is_tab {
|
||||||
|
eprintln!("Chunk text bytes: {:?}", chunk_text.as_bytes());
|
||||||
|
eprintln!("Tabs bitmap: {:#b}", tabs_bitmap);
|
||||||
|
assert_eq!(
|
||||||
|
has_bit, is_tab,
|
||||||
|
"Tabs bitmap mismatch at byte index {} in chunk {:?}. Byte: {:?}, Expected bit: {}, Got bit: {}",
|
||||||
|
byte_idx, chunk_text, byte as char, is_tab, has_bit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test(iterations = 100)]
|
||||||
|
fn test_random_chunk_bitmaps_with_diffs(cx: &mut App, mut rng: StdRng) {
|
||||||
|
use buffer_diff::BufferDiff;
|
||||||
|
use util::RandomCharIter;
|
||||||
|
|
||||||
|
let multibuffer = if rng.r#gen() {
|
||||||
|
let len = rng.gen_range(100..10000);
|
||||||
|
let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
|
||||||
|
let buffer = cx.new(|cx| Buffer::local(text, cx));
|
||||||
|
cx.new(|cx| MultiBuffer::singleton(buffer, cx))
|
||||||
|
} else {
|
||||||
|
MultiBuffer::build_random(&mut rng, cx)
|
||||||
|
};
|
||||||
|
|
||||||
|
let _diff_count = rng.gen_range(1..5);
|
||||||
|
let mut diffs = Vec::new();
|
||||||
|
|
||||||
|
multibuffer.update(cx, |multibuffer, cx| {
|
||||||
|
for buffer_id in multibuffer.excerpt_buffer_ids() {
|
||||||
|
if rng.gen_bool(0.7) {
|
||||||
|
if let Some(buffer_handle) = multibuffer.buffer(buffer_id) {
|
||||||
|
let buffer_text = buffer_handle.read(cx).text();
|
||||||
|
let mut base_text = String::new();
|
||||||
|
|
||||||
|
for line in buffer_text.lines() {
|
||||||
|
if rng.gen_bool(0.3) {
|
||||||
|
continue;
|
||||||
|
} else if rng.gen_bool(0.3) {
|
||||||
|
let line_len = rng.gen_range(0..50);
|
||||||
|
let modified_line = RandomCharIter::new(&mut rng)
|
||||||
|
.take(line_len)
|
||||||
|
.collect::<String>();
|
||||||
|
base_text.push_str(&modified_line);
|
||||||
|
base_text.push('\n');
|
||||||
|
} else {
|
||||||
|
base_text.push_str(line);
|
||||||
|
base_text.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rng.gen_bool(0.5) {
|
||||||
|
let extra_lines = rng.gen_range(1..5);
|
||||||
|
for _ in 0..extra_lines {
|
||||||
|
let line_len = rng.gen_range(0..50);
|
||||||
|
let extra_line = RandomCharIter::new(&mut rng)
|
||||||
|
.take(line_len)
|
||||||
|
.collect::<String>();
|
||||||
|
base_text.push_str(&extra_line);
|
||||||
|
base_text.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let diff =
|
||||||
|
cx.new(|cx| BufferDiff::new_with_base_text(&base_text, &buffer_handle, cx));
|
||||||
|
diffs.push(diff.clone());
|
||||||
|
multibuffer.add_diff(diff, cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
multibuffer.update(cx, |multibuffer, cx| {
|
||||||
|
if rng.gen_bool(0.5) {
|
||||||
|
multibuffer.set_all_diff_hunks_expanded(cx);
|
||||||
|
} else {
|
||||||
|
let snapshot = multibuffer.snapshot(cx);
|
||||||
|
let mut ranges = Vec::new();
|
||||||
|
for _ in 0..rng.gen_range(1..5) {
|
||||||
|
let start = rng.gen_range(0..snapshot.len());
|
||||||
|
let end = rng.gen_range(start..snapshot.len().min(start + 1000));
|
||||||
|
let start_anchor = snapshot.anchor_after(start);
|
||||||
|
let end_anchor = snapshot.anchor_before(end);
|
||||||
|
ranges.push(start_anchor..end_anchor);
|
||||||
|
}
|
||||||
|
multibuffer.expand_diff_hunks(ranges, cx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let snapshot = multibuffer.read(cx).snapshot(cx);
|
||||||
|
|
||||||
|
let chunks = snapshot.chunks(0..snapshot.len(), false);
|
||||||
|
|
||||||
|
for chunk in chunks {
|
||||||
|
let chunk_text = chunk.text;
|
||||||
|
let chars_bitmap = chunk.chars;
|
||||||
|
let tabs_bitmap = chunk.tabs;
|
||||||
|
|
||||||
|
if chunk_text.is_empty() {
|
||||||
|
assert_eq!(
|
||||||
|
chars_bitmap, 0,
|
||||||
|
"Empty chunk should have empty chars bitmap"
|
||||||
|
);
|
||||||
|
assert_eq!(tabs_bitmap, 0, "Empty chunk should have empty tabs bitmap");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
chunk_text.len() <= 128,
|
||||||
|
"Chunk text length {} exceeds 128 bytes",
|
||||||
|
chunk_text.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
let char_indices = chunk_text
|
||||||
|
.char_indices()
|
||||||
|
.map(|(i, _)| i)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for byte_idx in 0..chunk_text.len() {
|
||||||
|
let should_have_bit = char_indices.contains(&byte_idx);
|
||||||
|
let has_bit = chars_bitmap & (1 << byte_idx) != 0;
|
||||||
|
|
||||||
|
if has_bit != should_have_bit {
|
||||||
|
eprintln!("Chunk text bytes: {:?}", chunk_text.as_bytes());
|
||||||
|
eprintln!("Char indices: {:?}", char_indices);
|
||||||
|
eprintln!("Chars bitmap: {:#b}", chars_bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
has_bit, should_have_bit,
|
||||||
|
"Chars bitmap mismatch at byte index {} in chunk {:?}. Expected bit: {}, Got bit: {}",
|
||||||
|
byte_idx, chunk_text, should_have_bit, has_bit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
for (byte_idx, byte) in chunk_text.bytes().enumerate() {
|
for (byte_idx, byte) in chunk_text.bytes().enumerate() {
|
||||||
let is_tab = byte == b'\t';
|
let is_tab = byte == b'\t';
|
||||||
let has_bit = tabs_bitmap & (1 << byte_idx) != 0;
|
let has_bit = tabs_bitmap & (1 << byte_idx) != 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue