Skip to content

Commit

Permalink
move libz-rs-sys tests into its own crate
Browse files Browse the repository at this point in the history
  • Loading branch information
folkertdev committed Aug 9, 2024
1 parent 0cb9b35 commit 62b8703
Show file tree
Hide file tree
Showing 26 changed files with 299 additions and 34 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
members = [
"zlib-rs",
"libz-rs-sys",
"test-libz-rs-sys",
"dynamic-libz-sys",
]
exclude = [ ]
Expand Down Expand Up @@ -34,6 +35,6 @@ libz-sys = { version = "1.1.12", default-features = false, features = ["zlib-ng"
arbitrary = { version = "1.0" }
quickcheck = { version = "1.0.3", default-features = false, features = [] }

libz-rs-sys = { version = "0.2.1", path = "./libz-rs-sys", default-features = false }
zlib-rs = { version = "0.2.1", path = "./zlib-rs", default-features = false }
dynamic-libz-sys = { path = "./dynamic-libz-sys" }

9 changes: 1 addition & 8 deletions libz-rs-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,7 @@ c-allocator = ["zlib-rs/c-allocator"] # by default, use malloc/free for memory a
rust-allocator = ["zlib-rs/rust-allocator"] # by default, use the rust global alloctor for memory allocation
std = ["zlib-rs/std"] # assume `::std` is available
custom-prefix = [] # use the LIBZ_RS_SYS_PREFIX to prefix all exported symbols
testing-prefix = [] # prefix all symbols with LIBZ_RS_SYS_TEST_ for testing

[dependencies]
zlib-rs = { workspace = true, default-features = false }

[dev-dependencies]
zlib-rs = { workspace = true, default-features = false, features = ["std", "__internal-test"] }
libz-sys.workspace = true
libloading.workspace = true
dynamic-libz-sys.workspace = true
quickcheck.workspace = true
crc32fast = "1.3.2"
12 changes: 6 additions & 6 deletions libz-rs-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
//! always safe to provide an argument of type `&mut z_stream`: rust will automatically downcast
//! the argument to `*mut z_stream`.

#[cfg(test)]
mod tests;

use core::mem::MaybeUninit;

use core::ffi::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void};
Expand All @@ -39,17 +36,20 @@ macro_rules! prefix {
};
}

#[cfg(all(not(feature = "custom-prefix"), not(test)))]
#[cfg(all(
not(feature = "custom-prefix"),
not(any(test, feature = "testing-prefix"))
))]
macro_rules! prefix {
($name:expr) => {
stringify!($name)
};
}

#[cfg(all(not(feature = "custom-prefix"), test))]
#[cfg(all(not(feature = "custom-prefix"), any(test, feature = "testing-prefix")))]
macro_rules! prefix {
($name:expr) => {
concat!("LIBZ_RS_SYS_", stringify!($name))
concat!("LIBZ_RS_SYS_TEST_", stringify!($name))
};
}

Expand Down
23 changes: 23 additions & 0 deletions test-libz-rs-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "test-libz-rs-sys"
readme = "README.md"
description.workspace = true
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
publish.workspace = true
rust-version.workspace = true

[dev-dependencies]
quickcheck.workspace = true
crc32fast = "1.3.2"

zlib-rs = { workspace = true, default-features = false, features = ["std", "__internal-test"] }
libz-rs-sys = { workspace = true, default-features = false, features = ["std", "rust-allocator", "testing-prefix"] }

libloading.workspace = true
dynamic-libz-sys.workspace = true

libz-sys.workspace = true
7 changes: 7 additions & 0 deletions test-libz-rs-sys/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# tests for `libz-rs-sys`

**why are these tests here?**

Because C puts all symbols into one namespace. The `libz-rs-sys` crate defines the standard zlib api. But, we want to test against C implementations of that API. So we must, for testing, add a prefix to our names so that they don't clash with the symbols provided by the C implementation.

In this crate, our symbols are always distinct through some macro/feature flag magic. That means we can freely test and benchmark without any danger of mixing up the symbols.
203 changes: 203 additions & 0 deletions test-libz-rs-sys/examples/blogpost-compress.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
use std::ffi::{c_int, c_uint};

// we use the libz_sys but configure zlib-ng in zlib compat mode
use libz_sys as libz_ng_sys;

use zlib_rs::{DeflateFlush, ReturnCode};

fn main() {
let mut it = std::env::args();

// skips the program name
let _ = it.next().unwrap();

let level: i32 = it.next().unwrap().parse().unwrap();

let mut dest_vec = vec![0u8; 1 << 28];
let mut dest_len = dest_vec.len();

match it.next().unwrap().as_str() {
"ng" => {
let path = it.next().unwrap();
let input = std::fs::read(path).unwrap();

let err = compress_ng(&mut dest_vec, &mut dest_len, &input, level);
assert_eq!(ReturnCode::Ok, err);
}
"rs" => {
let path = it.next().unwrap();
let input = std::fs::read(path).unwrap();

let err = compress_rs(&mut dest_vec, &mut dest_len, &input, level);
assert_eq!(ReturnCode::Ok, err);
}
other => panic!("invalid input: {other:?}"),
}
}

const METHOD: i32 = zlib_rs::c_api::Z_DEFLATED;
const WINDOW_BITS: i32 = 15;
const MEM_LEVEL: i32 = 8;
const STRATEGY: i32 = zlib_rs::c_api::Z_DEFAULT_STRATEGY;

fn compress_rs(
dest: &mut [u8],
dest_len: &mut usize,
source: &[u8],
//
level: i32,
) -> ReturnCode {
use libz_rs_sys::{deflate, deflateEnd, deflateInit2_, z_stream, zlibVersion};

let mut stream = z_stream {
next_in: source.as_ptr() as *mut u8,
avail_in: 0, // for special logic in the first iteration
total_in: 0,
next_out: dest.as_mut_ptr(),
avail_out: 0, // for special logic on the first iteration
total_out: 0,
msg: std::ptr::null_mut(),
state: std::ptr::null_mut(),
zalloc: Some(zlib_rs::allocate::zalloc_c),
zfree: Some(zlib_rs::allocate::zfree_c),
opaque: std::ptr::null_mut(),
data_type: 0,
adler: 0,
reserved: 0,
};

let err = {
let strm: *mut z_stream = &mut stream;
unsafe {
deflateInit2_(
strm,
level,
METHOD,
WINDOW_BITS,
MEM_LEVEL,
STRATEGY,
zlibVersion(),
std::mem::size_of::<z_stream>() as c_int,
)
}
};

if ReturnCode::from(err) != ReturnCode::Ok as _ {
return ReturnCode::from(err);
}

let max = c_uint::MAX as usize;

let mut left = dest.len();
let mut source_len = source.len();

loop {
if stream.avail_out == 0 {
stream.avail_out = Ord::min(left, max) as _;
left -= stream.avail_out as usize;
}

if stream.avail_in == 0 {
stream.avail_in = Ord::min(source_len, max) as _;
source_len -= stream.avail_in as usize;
}

let flush = if source_len > 0 {
DeflateFlush::NoFlush
} else {
DeflateFlush::Finish
};

let err = unsafe { deflate(&mut stream, flush as i32) };
if ReturnCode::from(err) != ReturnCode::Ok {
break;
}
}

*dest_len = stream.total_out as _;

unsafe { deflateEnd(&mut stream) };

ReturnCode::Ok
}

fn compress_ng(
dest: &mut [u8],
dest_len: &mut usize,
source: &[u8],
//
level: i32,
) -> ReturnCode {
use libz_ng_sys::{deflate, deflateEnd, deflateInit2_, z_stream, zlibVersion};

let mut stream = z_stream {
next_in: source.as_ptr() as *mut u8,
avail_in: 0, // for special logic in the first iteration
total_in: 0,
next_out: dest.as_mut_ptr(),
avail_out: 0, // for special logic on the first iteration
total_out: 0,
msg: std::ptr::null_mut(),
state: std::ptr::null_mut(),
zalloc: zlib_rs::allocate::zalloc_c,
zfree: zlib_rs::allocate::zfree_c,
opaque: std::ptr::null_mut(),
data_type: 0,
adler: 0,
reserved: 0,
};

let err = {
let strm: *mut z_stream = &mut stream;
unsafe {
deflateInit2_(
strm,
level,
METHOD,
WINDOW_BITS,
MEM_LEVEL,
STRATEGY,
zlibVersion(),
std::mem::size_of::<z_stream>() as c_int,
)
}
};

if ReturnCode::from(err) != ReturnCode::Ok as _ {
return ReturnCode::from(err);
}

let max = c_uint::MAX as usize;

let mut left = dest.len();
let mut source_len = source.len();

loop {
if stream.avail_out == 0 {
stream.avail_out = Ord::min(left, max) as _;
left -= stream.avail_out as usize;
}

if stream.avail_in == 0 {
stream.avail_in = Ord::min(source_len, max) as _;
source_len -= stream.avail_in as usize;
}

let flush = if source_len > 0 {
DeflateFlush::NoFlush
} else {
DeflateFlush::Finish
};

let err = unsafe { deflate(&mut stream, flush as i32) };
if ReturnCode::from(err) != ReturnCode::Ok {
break;
}
}

*dest_len = stream.total_out as _;

unsafe { deflateEnd(&mut stream) };

ReturnCode::Ok
}
39 changes: 39 additions & 0 deletions test-libz-rs-sys/examples/blogpost-uncompress.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! a binary just so we can look at the optimized assembly

// we use the libz_sys but configure zlib-ng in zlib compat mode
use libz_sys as libz_ng_sys;

fn main() {
let mut it = std::env::args();

let _ = it.next().unwrap();

let mut dest_vec = vec![0u8; 1 << 28];

let mut dest_len = dest_vec.len() as std::ffi::c_ulong;
let dest = dest_vec.as_mut_ptr();

match it.next().unwrap().as_str() {
"ng" => {
let path = it.next().unwrap();
let input = std::fs::read(&path).unwrap();

let source = input.as_ptr();
let source_len = input.len() as _;

let err = unsafe { libz_ng_sys::uncompress(dest, &mut dest_len, source, source_len) };
assert_eq!(err, 0);
}
"rs" => {
let path = it.next().unwrap();
let input = std::fs::read(&path).unwrap();

let source = input.as_ptr();
let source_len = input.len() as _;

let err = unsafe { ::libz_rs_sys::uncompress(dest, &mut dest_len, source, source_len) };
assert_eq!(err, 0);
}
other => panic!("invalid option '{other}', expected one of 'rs' or 'ng'"),
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ use std::{ffi::CString, mem::MaybeUninit};
// we use the libz_sys but configure zlib-ng in zlib compat mode
use libz_sys as libz_ng_sys;

use crate as libz_rs_sys;

use core::ffi::{c_char, c_int, c_ulong, CStr};

use libz_rs_sys::{
Expand Down Expand Up @@ -887,7 +885,7 @@ fn test_dict_deflate() {

assert_eq!(ReturnCode::from(err), ReturnCode::Ok);

let dictId = strm.adler;
let dict_id = strm.adler;
let mut compr = [0; 32];
strm.next_out = compr.as_mut_ptr();
strm.avail_out = compr.len() as _;
Expand All @@ -901,7 +899,7 @@ fn test_dict_deflate() {
let err = deflateEnd(strm);
assert_eq!(ReturnCode::from(err), ReturnCode::Ok);

(dictId, compr)
(dict_id, compr)
};

let output_ng = unsafe {
Expand All @@ -928,7 +926,7 @@ fn test_dict_deflate() {

assert_eq!(ReturnCode::from(err), ReturnCode::Ok);

let dictId = strm.adler;
let dict_id = strm.adler;
let mut compr = [0; 32];
strm.next_out = compr.as_mut_ptr();
strm.avail_out = compr.len() as _;
Expand All @@ -942,7 +940,7 @@ fn test_dict_deflate() {
let err = libz_ng_sys::deflateEnd(strm);
assert_eq!(ReturnCode::from(err), ReturnCode::Ok);

(dictId, compr)
(dict_id, compr)
};

assert_eq!(output_rs.0, output_ng.0 as c_ulong);
Expand Down Expand Up @@ -1928,8 +1926,8 @@ fn gzip_with_header() {
}

mod fuzz_based_tests {
use crate::gz_header;
use crate::tests::helpers::compress_slice_ng;
use crate::helpers::compress_slice_ng;
use libz_rs_sys::gz_header;
use zlib_rs::{
deflate::{compress_slice, DeflateConfig, Method, Strategy},
ReturnCode,
Expand Down
File renamed without changes.
Loading

0 comments on commit 62b8703

Please sign in to comment.