Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 69 additions & 31 deletions tests/cpp_compat_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,80 @@ use fastpfor::rust::Integer as _;
use fastpfor::{cpp, rust};
use std::io::Cursor;

mod test_data;
use test_data::get_test_cases;

#[test]
fn test_rust_decompresses_cpp_encoded_data() {
let input: Vec<u32> = (0..256).map(|i| (i * 32) ^ (i >> 1)).collect();
let codec_cpp = cpp::FastPFor128Codec::new();
let mut codec_rs = rust::FastPFOR::new(rust::DEFAULT_PAGE_SIZE, rust::BLOCK_SIZE_128);

// Buffer for the C++ encoded
let mut compressed_buffer = vec![0; input.len()];
for input in get_test_cases(512 + rust::BLOCK_SIZE_128 as usize) {
// Buffer for the C++ encoded
let mut compressed_buffer = vec![0; input.len()];

// C++ encoding
let codec_cpp = cpp::FastPFor128Codec::new();
let encoded_cpp = codec_cpp.encode32(&input, &mut compressed_buffer).unwrap();
let compressed_len = encoded_cpp.len();
// C++ encoding
let encoded_cpp = codec_cpp.encode32(&input, &mut compressed_buffer).unwrap();
let compressed_len = encoded_cpp.len();

// C++ decoding
let mut decoded_by_cpp = vec![0; input.len()];
let decoded_cpp = codec_cpp
.decode32(encoded_cpp, &mut decoded_by_cpp)
.unwrap();
// C++ decoding
let mut decoded_by_cpp = vec![0; input.len()];
let decoded_cpp = codec_cpp
.decode32(encoded_cpp, &mut decoded_by_cpp)
.unwrap();

// Rust decoding
let mut input_offset = Cursor::new(0u32);
let mut decoded_by_rust = vec![0; input.len()];
codec_rs
.uncompress(
&compressed_buffer,
compressed_len as u32,
&mut input_offset,
&mut decoded_by_rust,
&mut Cursor::new(0u32),
)
.unwrap();

assert_eq!(
decoded_cpp.len(),
decoded_by_rust.len(),
"Mismatched output lengths"
);
assert_eq!(decoded_cpp, decoded_by_rust);
}
}

// Rust decoding
let mut input_offset = Cursor::new(0u32);
#[test]
fn test_rust_and_cpp_fastpfor32_compression_matches() {
let codec_cpp = cpp::FastPFor128Codec::new();
let mut codec_rs = rust::FastPFOR::new(rust::DEFAULT_PAGE_SIZE, rust::BLOCK_SIZE_128);
let mut decoded_by_rust = vec![0; input.len()];
codec_rs
.uncompress(
&compressed_buffer,
compressed_len as u32,
&mut input_offset,
&mut decoded_by_rust,
&mut Cursor::new(0u32),
)
.unwrap();

assert_eq!(
decoded_cpp.len(),
decoded_by_rust.len(),
"Mismatched output lengths"
);
assert_eq!(decoded_cpp, decoded_by_rust);

for input in get_test_cases(512 + rust::BLOCK_SIZE_128 as usize) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while totally not critical, and probably good for another PR, but it seems it might benefit us in the future to come up with some trait-based API that is the same for both rust and cpp implementation... ideas are welcome

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely agreed. For now, I need to apply a small workaround due to the interface between the rust-native implementation and the rust wrapper. A key issue is that the current rust-native code does not support arbitrary input lengths. The cpp implementation appears to tolerate such cases. I have added this to my to-do list once I better understand the algorithm.

// Buffer for the C++ encoded
let mut compressed_buffer = vec![0; input.len()];

// C++ encoding
let encoded_cpp = codec_cpp.encode32(&input, &mut compressed_buffer).unwrap();
let compressed_len = encoded_cpp.len();

// Rust encoding
let mut input_offset_rs = Cursor::new(0u32);
let mut encoded_rs: Vec<u32> = vec![0; input.len()];
let mut output_offset_rs = Cursor::new(0u32);
codec_rs
.compress(
&input,
input.len() as u32,
&mut input_offset_rs,
&mut encoded_rs,
&mut output_offset_rs,
)
.unwrap();

assert_eq!(
&encoded_cpp[..compressed_len],
&encoded_rs[..compressed_len]
);
}
}
45 changes: 45 additions & 0 deletions tests/test_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#![cfg(all(feature = "rust", feature = "cpp"))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think its better to move this to tests/common.rs

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


use rand::rngs::StdRng;
use rand::Rng as _;
use rand::SeedableRng as _;

pub fn get_test_cases(n: usize) -> Vec<Vec<u32>> {
let mut rng = StdRng::seed_from_u64(14);

vec![
// Zeroes
vec![0u32; n],
// Same non-zero
vec![14u32; n],
// Ascending values
(0..n).map(|i| i as u32).collect::<Vec<u32>>(),
// Descending values
(0..n).rev().map(|i| i as u32).collect::<Vec<u32>>(),
// Bit-flipping pattern
(0..n)
.map(|i| ((i as u32) * 32) ^ ((i as u32) >> 1))
.collect::<Vec<u32>>(),
// Alternating large and small values
(0..n)
.map(|i| {
let ui = i as u32;
if ui % 2 == 0 {
1 << 30
} else {
3
}
})
.collect::<Vec<u32>>(),
// Random u32 values
(0..n)
.map(|_| rng.random_range(0..(1 << 31)))
.collect::<Vec<u32>>(),
// Spike in the middle
(0..n)
.map(|i| if i == n / 2 { u32::MAX } else { 1 })
.collect::<Vec<u32>>(),
// An empty vector
Vec::new(),
]
}
Loading