112a9d9c8Sopenharmony_ci# Write a Sanity Test
212a9d9c8Sopenharmony_ci
312a9d9c8Sopenharmony_ciFinally, to tie everything together, let's write a sanity test that round trips
412a9d9c8Sopenharmony_cisome text through compression and decompression, and then asserts that it came
512a9d9c8Sopenharmony_ciback out the same as it went in. This is a little wordy using the raw FFI
612a9d9c8Sopenharmony_cibindings, but hopefully we wouldn't usually ask people to do this, we'd provide
712a9d9c8Sopenharmony_cia nice Rust-y API on top of the raw FFI bindings for them. However, since this
812a9d9c8Sopenharmony_ciis for testing the bindings directly, our sanity test will use the bindings
912a9d9c8Sopenharmony_cidirectly.
1012a9d9c8Sopenharmony_ci
1112a9d9c8Sopenharmony_ciThe test data I'm round tripping are some Futurama quotes I got off the internet
1212a9d9c8Sopenharmony_ciand put in the `futurama-quotes.txt` file, which is read into a `&'static str`
1312a9d9c8Sopenharmony_ciat compile time via the `include_str!("../futurama-quotes.txt")` macro
1412a9d9c8Sopenharmony_ciinvocation.
1512a9d9c8Sopenharmony_ci
1612a9d9c8Sopenharmony_ciWithout further ado, here is the test, which should be appended to the bottom of
1712a9d9c8Sopenharmony_ciour `src/lib.rs` file:
1812a9d9c8Sopenharmony_ci
1912a9d9c8Sopenharmony_ci```rust
2012a9d9c8Sopenharmony_ci#[cfg(test)]
2112a9d9c8Sopenharmony_cimod tests {
2212a9d9c8Sopenharmony_ci    use super::*;
2312a9d9c8Sopenharmony_ci    use std::mem;
2412a9d9c8Sopenharmony_ci
2512a9d9c8Sopenharmony_ci    #[test]
2612a9d9c8Sopenharmony_ci    fn round_trip_compression_decompression() {
2712a9d9c8Sopenharmony_ci        unsafe {
2812a9d9c8Sopenharmony_ci            let input = include_str!("../futurama-quotes.txt").as_bytes();
2912a9d9c8Sopenharmony_ci            let mut compressed_output: Vec<u8> = vec![0; input.len()];
3012a9d9c8Sopenharmony_ci            let mut decompressed_output: Vec<u8> = vec![0; input.len()];
3112a9d9c8Sopenharmony_ci
3212a9d9c8Sopenharmony_ci            // Construct a compression stream.
3312a9d9c8Sopenharmony_ci            let mut stream: bz_stream = mem::zeroed();
3412a9d9c8Sopenharmony_ci            let result = BZ2_bzCompressInit(&mut stream as *mut _,
3512a9d9c8Sopenharmony_ci                                            1,   // 1 x 100000 block size
3612a9d9c8Sopenharmony_ci                                            4,   // verbosity (4 = most verbose)
3712a9d9c8Sopenharmony_ci                                            0);  // default work factor
3812a9d9c8Sopenharmony_ci            match result {
3912a9d9c8Sopenharmony_ci                r if r == (BZ_CONFIG_ERROR as _) => panic!("BZ_CONFIG_ERROR"),
4012a9d9c8Sopenharmony_ci                r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
4112a9d9c8Sopenharmony_ci                r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),
4212a9d9c8Sopenharmony_ci                r if r == (BZ_OK as _) => {},
4312a9d9c8Sopenharmony_ci                r => panic!("Unknown return value = {}", r),
4412a9d9c8Sopenharmony_ci            }
4512a9d9c8Sopenharmony_ci
4612a9d9c8Sopenharmony_ci            // Compress `input` into `compressed_output`.
4712a9d9c8Sopenharmony_ci            stream.next_in = input.as_ptr() as *mut _;
4812a9d9c8Sopenharmony_ci            stream.avail_in = input.len() as _;
4912a9d9c8Sopenharmony_ci            stream.next_out = compressed_output.as_mut_ptr() as *mut _;
5012a9d9c8Sopenharmony_ci            stream.avail_out = compressed_output.len() as _;
5112a9d9c8Sopenharmony_ci            let result = BZ2_bzCompress(&mut stream as *mut _, BZ_FINISH as _);
5212a9d9c8Sopenharmony_ci            match result {
5312a9d9c8Sopenharmony_ci                r if r == (BZ_RUN_OK as _) => panic!("BZ_RUN_OK"),
5412a9d9c8Sopenharmony_ci                r if r == (BZ_FLUSH_OK as _) => panic!("BZ_FLUSH_OK"),
5512a9d9c8Sopenharmony_ci                r if r == (BZ_FINISH_OK as _) => panic!("BZ_FINISH_OK"),
5612a9d9c8Sopenharmony_ci                r if r == (BZ_SEQUENCE_ERROR as _) => panic!("BZ_SEQUENCE_ERROR"),
5712a9d9c8Sopenharmony_ci                r if r == (BZ_STREAM_END as _) => {},
5812a9d9c8Sopenharmony_ci                r => panic!("Unknown return value = {}", r),
5912a9d9c8Sopenharmony_ci            }
6012a9d9c8Sopenharmony_ci
6112a9d9c8Sopenharmony_ci            // Finish the compression stream.
6212a9d9c8Sopenharmony_ci            let result = BZ2_bzCompressEnd(&mut stream as *mut _);
6312a9d9c8Sopenharmony_ci            match result {
6412a9d9c8Sopenharmony_ci                r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
6512a9d9c8Sopenharmony_ci                r if r == (BZ_OK as _) => {},
6612a9d9c8Sopenharmony_ci                r => panic!("Unknown return value = {}", r),
6712a9d9c8Sopenharmony_ci            }
6812a9d9c8Sopenharmony_ci
6912a9d9c8Sopenharmony_ci            // Construct a decompression stream.
7012a9d9c8Sopenharmony_ci            let mut stream: bz_stream = mem::zeroed();
7112a9d9c8Sopenharmony_ci            let result = BZ2_bzDecompressInit(&mut stream as *mut _,
7212a9d9c8Sopenharmony_ci                                              4,   // verbosity (4 = most verbose)
7312a9d9c8Sopenharmony_ci                                              0);  // default small factor
7412a9d9c8Sopenharmony_ci            match result {
7512a9d9c8Sopenharmony_ci                r if r == (BZ_CONFIG_ERROR as _) => panic!("BZ_CONFIG_ERROR"),
7612a9d9c8Sopenharmony_ci                r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
7712a9d9c8Sopenharmony_ci                r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),
7812a9d9c8Sopenharmony_ci                r if r == (BZ_OK as _) => {},
7912a9d9c8Sopenharmony_ci                r => panic!("Unknown return value = {}", r),
8012a9d9c8Sopenharmony_ci            }
8112a9d9c8Sopenharmony_ci
8212a9d9c8Sopenharmony_ci            // Decompress `compressed_output` into `decompressed_output`.
8312a9d9c8Sopenharmony_ci            stream.next_in = compressed_output.as_ptr() as *mut _;
8412a9d9c8Sopenharmony_ci            stream.avail_in = compressed_output.len() as _;
8512a9d9c8Sopenharmony_ci            stream.next_out = decompressed_output.as_mut_ptr() as *mut _;
8612a9d9c8Sopenharmony_ci            stream.avail_out = decompressed_output.len() as _;
8712a9d9c8Sopenharmony_ci            let result = BZ2_bzDecompress(&mut stream as *mut _);
8812a9d9c8Sopenharmony_ci            match result {
8912a9d9c8Sopenharmony_ci                r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
9012a9d9c8Sopenharmony_ci                r if r == (BZ_DATA_ERROR as _) => panic!("BZ_DATA_ERROR"),
9112a9d9c8Sopenharmony_ci                r if r == (BZ_DATA_ERROR_MAGIC as _) => panic!("BZ_DATA_ERROR"),
9212a9d9c8Sopenharmony_ci                r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),
9312a9d9c8Sopenharmony_ci                r if r == (BZ_OK as _) => panic!("BZ_OK"),
9412a9d9c8Sopenharmony_ci                r if r == (BZ_STREAM_END as _) => {},
9512a9d9c8Sopenharmony_ci                r => panic!("Unknown return value = {}", r),
9612a9d9c8Sopenharmony_ci            }
9712a9d9c8Sopenharmony_ci
9812a9d9c8Sopenharmony_ci            // Close the decompression stream.
9912a9d9c8Sopenharmony_ci            let result = BZ2_bzDecompressEnd(&mut stream as *mut _);
10012a9d9c8Sopenharmony_ci            match result {
10112a9d9c8Sopenharmony_ci                r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),
10212a9d9c8Sopenharmony_ci                r if r == (BZ_OK as _) => {},
10312a9d9c8Sopenharmony_ci                r => panic!("Unknown return value = {}", r),
10412a9d9c8Sopenharmony_ci            }
10512a9d9c8Sopenharmony_ci
10612a9d9c8Sopenharmony_ci            assert_eq!(input, &decompressed_output[..]);
10712a9d9c8Sopenharmony_ci        }
10812a9d9c8Sopenharmony_ci    }
10912a9d9c8Sopenharmony_ci}
11012a9d9c8Sopenharmony_ci```
11112a9d9c8Sopenharmony_ci
11212a9d9c8Sopenharmony_ciNow let's run `cargo test` again and verify that everything is linking and binding
11312a9d9c8Sopenharmony_ciproperly!
11412a9d9c8Sopenharmony_ci
11512a9d9c8Sopenharmony_ci```bash
11612a9d9c8Sopenharmony_ci$ cargo test
11712a9d9c8Sopenharmony_ci   Compiling bindgen-tutorial-bzip2-sys v0.1.0
11812a9d9c8Sopenharmony_ci    Finished debug [unoptimized + debuginfo] target(s) in 0.54 secs
11912a9d9c8Sopenharmony_ci     Running target/debug/deps/bindgen_tutorial_bzip2_sys-1c5626bbc4401c3a
12012a9d9c8Sopenharmony_ci
12112a9d9c8Sopenharmony_cirunning 15 tests
12212a9d9c8Sopenharmony_citest bindgen_test_layout___darwin_pthread_handler_rec ... ok
12312a9d9c8Sopenharmony_citest bindgen_test_layout___sFILE ... ok
12412a9d9c8Sopenharmony_citest bindgen_test_layout___sbuf ... ok
12512a9d9c8Sopenharmony_citest bindgen_test_layout__bindgen_ty_1 ... ok
12612a9d9c8Sopenharmony_citest bindgen_test_layout__bindgen_ty_2 ... ok
12712a9d9c8Sopenharmony_citest bindgen_test_layout__opaque_pthread_attr_t ... ok
12812a9d9c8Sopenharmony_citest bindgen_test_layout__opaque_pthread_cond_t ... ok
12912a9d9c8Sopenharmony_citest bindgen_test_layout__opaque_pthread_condattr_t ... ok
13012a9d9c8Sopenharmony_citest bindgen_test_layout__opaque_pthread_mutex_t ... ok
13112a9d9c8Sopenharmony_citest bindgen_test_layout__opaque_pthread_mutexattr_t ... ok
13212a9d9c8Sopenharmony_citest bindgen_test_layout__opaque_pthread_once_t ... ok
13312a9d9c8Sopenharmony_citest bindgen_test_layout__opaque_pthread_rwlock_t ... ok
13412a9d9c8Sopenharmony_citest bindgen_test_layout__opaque_pthread_rwlockattr_t ... ok
13512a9d9c8Sopenharmony_citest bindgen_test_layout__opaque_pthread_t ... ok
13612a9d9c8Sopenharmony_ci    block 1: crc = 0x47bfca17, combined CRC = 0x47bfca17, size = 2857
13712a9d9c8Sopenharmony_ci        bucket sorting ...
13812a9d9c8Sopenharmony_ci        depth      1 has   2849 unresolved strings
13912a9d9c8Sopenharmony_ci        depth      2 has   2702 unresolved strings
14012a9d9c8Sopenharmony_ci        depth      4 has   1508 unresolved strings
14112a9d9c8Sopenharmony_ci        depth      8 has    538 unresolved strings
14212a9d9c8Sopenharmony_ci        depth     16 has    148 unresolved strings
14312a9d9c8Sopenharmony_ci        depth     32 has      0 unresolved strings
14412a9d9c8Sopenharmony_ci        reconstructing block ...
14512a9d9c8Sopenharmony_ci      2857 in block, 2221 after MTF & 1-2 coding, 61+2 syms in use
14612a9d9c8Sopenharmony_ci      initial group 5, [0 .. 1], has 570 syms (25.7%)
14712a9d9c8Sopenharmony_ci      initial group 4, [2 .. 2], has 256 syms (11.5%)
14812a9d9c8Sopenharmony_ci      initial group 3, [3 .. 6], has 554 syms (24.9%)
14912a9d9c8Sopenharmony_ci      initial group 2, [7 .. 12], has 372 syms (16.7%)
15012a9d9c8Sopenharmony_ci      initial group 1, [13 .. 62], has 469 syms (21.1%)
15112a9d9c8Sopenharmony_ci      pass 1: size is 2743, grp uses are 13 6 15 0 11
15212a9d9c8Sopenharmony_ci      pass 2: size is 1216, grp uses are 13 7 15 0 10
15312a9d9c8Sopenharmony_ci      pass 3: size is 1214, grp uses are 13 8 14 0 10
15412a9d9c8Sopenharmony_ci      pass 4: size is 1213, grp uses are 13 9 13 0 10
15512a9d9c8Sopenharmony_ci      bytes: mapping 19, selectors 17, code lengths 79, codes 1213
15612a9d9c8Sopenharmony_ci    final combined CRC = 0x47bfca17
15712a9d9c8Sopenharmony_ci
15812a9d9c8Sopenharmony_ci    [1: huff+mtf rt+rld {0x47bfca17, 0x47bfca17}]
15912a9d9c8Sopenharmony_ci    combined CRCs: stored = 0x47bfca17, computed = 0x47bfca17
16012a9d9c8Sopenharmony_citest tests::round_trip_compression_decompression ... ok
16112a9d9c8Sopenharmony_ci
16212a9d9c8Sopenharmony_citest result: ok. 15 passed; 0 failed; 0 ignored; 0 measured
16312a9d9c8Sopenharmony_ci
16412a9d9c8Sopenharmony_ci   Doc-tests bindgen-tutorial-bzip2-sys
16512a9d9c8Sopenharmony_ci
16612a9d9c8Sopenharmony_cirunning 0 tests
16712a9d9c8Sopenharmony_ci
16812a9d9c8Sopenharmony_citest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
16912a9d9c8Sopenharmony_ci```
170