/// Run fuzzers with `cargo test --release -- --ignored --test fuzzer` extern crate serde; extern crate serde_bytes; #[macro_use] extern crate serde_derive; extern crate zlo; use std::fmt::Debug; use std::collections::HashMap; use std::borrow::Cow; use zlo::{Infinite, Bounded}; use zlo::{serialized_size, Error, Result}; use zlo::{serialize, deserialize, deserialize_from}; fn the_same(element: V) where V: serde::Serialize+serde::de::DeserializeOwned+PartialEq+Debug+'static { let encoded = serialize(&element, Infinite).unwrap(); let decoded = deserialize(&encoded[..]).unwrap(); assert_eq!(element, decoded); } #[test] fn test_numbers() { // unsigned positive the_same(5u8); the_same(5u16); the_same(5u32); the_same(5u64); the_same(5usize); // signed positive the_same(5i8); the_same(5i16); the_same(5i32); the_same(5i64); the_same(5isize); // signed negative the_same(-5i8); the_same(-5i16); the_same(-5i32); the_same(-5i64); the_same(-5isize); // floating the_same(-100f32); the_same(0f32); the_same(5f32); the_same(-100f64); the_same(5f64); } #[test] fn test_string() { the_same("".to_string()); the_same("a".to_string()); } #[test] fn test_tuple() { the_same((1isize,)); the_same((1isize, 2isize, 3isize)); the_same((1isize, "foo".to_string(), ())); } #[test] fn test_basic_struct() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Easy { x: isize, s: String, y: usize } the_same(Easy{x: -4, s: "foo".to_string(), y: 10}); } #[test] fn test_nested_struct() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Easy { x: isize, s: String, y: usize } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Nest { f: Easy, b: usize, s: Easy } the_same(Nest { f: Easy {x: -1, s: "foo".to_string(), y: 20}, b: 100, s: Easy {x: -100, s: "bar".to_string(), y: 20} }); } #[test] fn test_struct_newtype() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct NewtypeStr(usize); the_same(NewtypeStr(5)); } #[test] fn test_struct_tuple() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct TubStr(usize, String, f32); the_same(TubStr(5, "hello".to_string(), 3.2)); } #[test] fn test_option() { the_same(Some(5usize)); the_same(Some("foo bar".to_string())); the_same(None::); } #[test] fn test_enum() { #[derive(Serialize, Deserialize, PartialEq, Debug)] enum TestEnum { NoArg, OneArg(usize), Args(usize, usize), AnotherNoArg, StructLike{x: usize, y: f32} } the_same(TestEnum::NoArg); the_same(TestEnum::OneArg(4)); the_same(TestEnum::Args(4, 5)); the_same(TestEnum::AnotherNoArg); the_same(TestEnum::StructLike{x: 4, y: 3.14159}); the_same([TestEnum::NoArg, TestEnum::OneArg(5), TestEnum::AnotherNoArg, TestEnum::StructLike{x: 4, y:1.4}]); } #[test] fn test_vec() { let v: Vec = vec![]; the_same(v); the_same(vec![1u64]); the_same(vec![1u64,2,3,4,5,6]); } #[test] fn test_map() { let mut m = HashMap::new(); m.insert(4u64, "foo".to_string()); m.insert(0u64, "bar".to_string()); the_same(m); } #[test] fn test_bool() { the_same(true); the_same(false); } #[test] fn test_unicode() { the_same("å".to_string()); the_same("aåååååååa".to_string()); } #[test] fn test_fixed_size_array() { the_same([24u32; 32]); the_same([1u64, 2, 3, 4, 5, 6, 7, 8]); the_same([0u8; 19]); } #[test] fn deserializing_errors() { fn isize_invalid_deserialize(res: Result) { match res { Err(Error::InvalidEncoding{..}) => {}, Err(Error::Custom(ref s)) if s.contains("invalid encoding") => {}, Err(Error::Custom(ref s)) if s.contains("invalid value") => {}, other => panic!("Expecting InvalidEncoding, got {:?}", other), } } isize_invalid_deserialize(deserialize::(&[3, 0, 0xff, 0xff, 0xff, 0xff])); // Out-of-bounds variant #[derive(Serialize, Deserialize, Debug)] enum Test { One, Two, }; isize_invalid_deserialize(deserialize::(&[0xff; 5])); } #[test] fn char_serialization() { let chars = "Aa\0☺♪"; for c in chars.chars() { let encoded = serialize(&c, Bounded::new_bytes(4)).expect("serializing char failed"); let decoded: char = deserialize(&encoded).expect("deserializing failed"); assert_eq!(decoded, c); } } #[test] fn too_big_char_deserialize() { let serialized = [0x41]; let deserialized: Result = deserialize_from(&mut &serialized[..], Bounded::new_bytes(1)); assert!(deserialized.is_ok()); assert_eq!(deserialized.unwrap(), 'A'); } #[test] fn too_big_serialize() { assert!(serialize(&1u32, Bounded::new_bytes(1)).is_err()); assert!(serialize(&2u32, Bounded::new_bytes(2)).is_ok()); assert!(serialize(&"abcde", Bounded::new_bytes(2 + 4)).is_err()); assert!(serialize(&"abcde", Bounded::new_bytes(2 + 5)).is_ok()); } #[test] fn test_proxy_encoded_size() { assert_eq!(1, serialized_size(&0u8)); assert_eq!(1, serialized_size(&0u16)); assert_eq!(1, serialized_size(&0u32)); assert_eq!(1, serialized_size(&0u64)); // integers are written as 1 bit + 8 bit data + 1 bit early terminator assert_eq!(9, serialized_size(&1u8)); assert_eq!(10, serialized_size(&1u16)); assert_eq!(10, serialized_size(&1u32)); assert_eq!(10, serialized_size(&1u64)); // last terminator is never written assert_eq!(1 * 9, serialized_size(&0xffu8)); assert_eq!(2 * 9, serialized_size(&0xffffu16)); assert_eq!(4 * 9, serialized_size(&0xffffffffu32)); assert_eq!(8 * 9, serialized_size(&0xffffffffffffffffu64)); // length isize stored as u64 assert_eq!(1, serialized_size(&"")); assert_eq!(10 + 8, serialized_size(&"a")); assert_eq!(10 * 2 + 1, serialized_size(&[0u32, 1u32, 2u32])); } #[test] fn test_size_predictions() { macro_rules! assert_8 { ($a:expr, $b:expr) => { assert_eq!($a, ($b + 7) / 8) } } // verify that serialized_size returns size within range of 1 byte from real // size assert_8!(serialize(&0u8, Infinite).unwrap().len() as u64, serialized_size(&0u8)); assert_8!(serialize(&0u16, Infinite).unwrap().len() as u64, serialized_size(&0u16)); assert_8!(serialize(&0u32, Infinite).unwrap().len() as u64, serialized_size(&0u32)); assert_8!(serialize(&0u64, Infinite).unwrap().len() as u64, serialized_size(&0u64)); // integers are written as 1 bit + 8 bit data + 1 bit early terminator assert_8!(serialize(&1u8, Infinite).unwrap().len() as u64, serialized_size(&1u8)); assert_8!(serialize(&1u16, Infinite).unwrap().len() as u64, serialized_size(&1u16)); assert_8!(serialize(&1u32, Infinite).unwrap().len() as u64, serialized_size(&1u32)); assert_8!(serialize(&1u64, Infinite).unwrap().len() as u64, serialized_size(&1u64)); // last terminator is never written assert_8!(serialize(&0xffu8, Infinite).unwrap().len() as u64, serialized_size(&0xffu8)); assert_8!(serialize(&0xffffu16, Infinite).unwrap().len() as u64, serialized_size(&0xffffu16)); assert_8!(serialize(&0xffffffffu32, Infinite).unwrap().len() as u64, serialized_size(&0xffffffffu32)); assert_8!(serialize(&0xffffffffffffffffu64, Infinite).unwrap().len() as u64, serialized_size(&0xffffffffffffffffu64)); // length isize stored as u64 assert_8!(serialize(&"", Infinite).unwrap().len() as u64, serialized_size(&"")); assert_8!(serialize(&"a", Infinite).unwrap().len() as u64, serialized_size(&"a")); assert_8!(serialize(&[0u32, 1u32, 2u32], Infinite).unwrap().len() as u64, serialized_size(&[0u32, 1u32, 2u32])); } #[test] fn encode_box() { the_same(Box::new(5)); } #[test] fn test_cow_serialize() { let large_object = vec![1u32,2,3,4,5,6]; let mut large_map = HashMap::new(); large_map.insert(1, 2); #[derive(Serialize, Deserialize, Debug)] enum Message<'a> { M1(Cow<'a, Vec>), M2(Cow<'a, HashMap>) } // Test 1 { let serialized = serialize(&Message::M1(Cow::Borrowed(&large_object)), Infinite).unwrap(); let deserialized: Message<'static> = deserialize_from(&mut &serialized[..], Infinite).unwrap(); match deserialized { Message::M1(b) => assert_eq!(&b.into_owned(), &large_object), _ => assert!(false) } } // Test 2 { let serialized = serialize(&Message::M2(Cow::Borrowed(&large_map)), Infinite).unwrap(); let deserialized: Message<'static> = deserialize_from(&mut &serialized[..], Infinite).unwrap(); match deserialized { Message::M2(b) => assert_eq!(&b.into_owned(), &large_map), _ => assert!(false) } } } #[test] fn test_strbox_serialize() { let strx: &'static str = "hello world"; let serialized = serialize(&Cow::Borrowed(strx), Infinite).unwrap(); let deserialized: Cow<'static, String> = deserialize_from(&mut &serialized[..], Infinite).unwrap(); let stringx: String = deserialized.into_owned(); assert!(strx == &stringx[..]); } #[test] fn test_slicebox_serialize() { let slice = [1u32, 2, 3 ,4, 5]; let serialized = serialize(&Cow::Borrowed(&slice[..]), Infinite).unwrap(); println!("{:?}", serialized); let deserialized: Cow<'static, Vec> = deserialize_from(&mut &serialized[..], Infinite).unwrap(); { let sb: &[u32] = &deserialized; assert!(slice == sb); } let vecx: Vec = deserialized.into_owned(); assert!(slice == &vecx[..]); } #[test] fn test_multi_strings_serialize() { assert!(serialize(&("foo", "bar", "baz"), Infinite).is_ok()); } #[test] fn test_oom_protection() { use std::io::Cursor; #[derive(Serialize, Deserialize, PartialEq, Debug)] struct FakeVec { len: u64, byte: u8 } let x = serialize(&FakeVec { len: 0xffffffffffffffffu64, byte: 1 }, Bounded::new_bytes(11)).unwrap(); let y: Result> = deserialize_from(&mut Cursor::new(&x[..]), Bounded::new_bytes(11)); assert!(y.is_err()); } #[test] fn path_buf() { use std::path::{Path, PathBuf}; let path = Path::new("foo").to_path_buf(); let serde_encoded = serialize(&path, Infinite).unwrap(); let decoded: PathBuf = deserialize(&serde_encoded).unwrap(); assert!(path.to_str() == decoded.to_str()); } #[test] fn serde_bytes() { use serde_bytes::ByteBuf; the_same(ByteBuf::from(vec![1,2,3,4,5])); } #[test] #[ignore] fn fuzzer_f32() { let mut buf = vec![]; for exp in 0 .. 0xff { for frac in (0 .. 0xffff).flat_map(|x| (0 .. 0xf).map(move |y| (x << 7) | y)) { assert_eq!(frac >> 23, 0); buf.clear(); let bits = 0x80000000 | (exp << 23) | frac; let x = f32::from_bits(bits); zlo::serialize_into(&mut buf, &x, Infinite).unwrap(); let a: f32 = zlo::deserialize(&buf).unwrap(); assert_eq!(x.to_bits(), a.to_bits()); } println!("fuzzer_f32\t{}", exp * 100 / 0xff); } } #[test] #[ignore] fn fuzzer_f64() { let mut buf = vec![]; for exp in 0 .. 0x800_u64 { for frac in (0 .. 0xff) .map(|x| x << 44) .flat_map(|x| (0 .. 0xf).map(move |y| x | y)) { assert_eq!(frac >> 52, 0); buf.clear(); let bits = 0x8000000000000000 | (exp << 52) | frac; let x = f64::from_bits(bits); zlo::serialize_into(&mut buf, &x, Infinite).unwrap(); let a: f64 = zlo::deserialize(&buf).unwrap(); assert_eq!(x.to_bits(), a.to_bits()); } println!("fuzzer_f64\t{}", exp * 100 / 0x800); } }