#[macro_use] extern crate serde_derive; extern crate serde_qs as qs; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] struct Address { city: String, street: String, postcode: String, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] struct QueryParams { id: u8, name: String, phone: u32, address: Address, user_ids: Vec, } #[test] fn serialize_struct() { let params = QueryParams { id: 42, name: "Acme".to_string(), phone: 12345, address: Address { city: "Carrot City".to_string(), street: "Special-Street* No. 11".to_string(), postcode: "12345".to_string(), }, user_ids: vec![1, 2, 3, 4], }; assert_eq!( qs::to_string(¶ms).unwrap(), "\ id=42&name=Acme&phone=12345&address[city]=Carrot+City&\ address[street]=Special-Street*+No.+11&\ address[postcode]=12345&user_ids[0]=1&user_ids[1]=2&\ user_ids[2]=3&user_ids[3]=4" ); } #[test] fn serialize_option() { #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Query { vec: Option>, } let params = ""; let query = Query { vec: None }; let rec_params = qs::to_string(&query).unwrap(); assert_eq!(rec_params, params); let params = "vec[0]=1&vec[1]=2"; let query = Query { vec: Some(vec![1, 2]), }; let rec_params = qs::to_string(&query).unwrap(); assert_eq!(rec_params, params); } #[test] fn serialize_enum() { #[derive(Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "lowercase")] enum TestEnum { A, B(bool), C { x: u8, y: u8 }, D(u8, u8), } #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Query { e: TestEnum, } let params = "e=a"; let query = Query { e: TestEnum::A }; let rec_params = qs::to_string(&query).unwrap(); assert_eq!(rec_params, params); let params = "e[b]=true"; let query = Query { e: TestEnum::B(true), }; let rec_params = qs::to_string(&query).unwrap(); assert_eq!(rec_params, params); let params = "e[c][x]=2&e[c][y]=3"; let query = Query { e: TestEnum::C { x: 2, y: 3 }, }; let rec_params = qs::to_string(&query).unwrap(); assert_eq!(rec_params, params); let params = "e[d][0]=128&e[d][1]=1"; let query = Query { e: TestEnum::D(128, 1), }; let rec_params = qs::to_string(&query).unwrap(); assert_eq!(rec_params, params); } #[test] fn serialize_flatten() { #[derive(Deserialize, Serialize, Debug, PartialEq)] struct Query { a: u8, #[serde(flatten)] common: CommonParams, } #[derive(Deserialize, Serialize, Debug, PartialEq)] struct CommonParams { limit: u64, offset: u64, } let params = "a=1&limit=100&offset=50"; let query = Query { a: 1, common: CommonParams { limit: 100, offset: 50, }, }; let rec_params = qs::to_string(&query).unwrap(); assert_eq!(rec_params, params); } #[test] fn serialize_map_with_unit_enum_keys() { use std::collections::HashMap; #[derive(Serialize, Eq, PartialEq, Hash)] enum Operator { Lt, Gt, } #[derive(Serialize)] struct Filter { point: HashMap, } let mut map = HashMap::new(); map.insert(Operator::Gt, 123); map.insert(Operator::Lt, 321); let test = Filter { point: map }; let query = qs::to_string(&test).unwrap(); assert!(query == "point[Lt]=321&point[Gt]=123" || query == "point[Gt]=123&point[Lt]=321"); } #[test] fn serialize_bytes() { struct Bytes(&'static [u8]); #[derive(Serialize)] struct Query { bytes: Bytes, } impl serde::Serialize for Bytes { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.serialize_bytes(self.0) } } let bytes = Bytes(b"hello, world!"); let s = qs::to_string(&Query { bytes }).unwrap(); assert_eq!(s, "bytes=hello%2C+world%21"); } #[test] fn serialize_hashmap_keys() { // Issue: https://github.com/samscott89/serde_qs/issues/45 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] struct HashParams { attrs: std::collections::HashMap, } let data = HashParams { attrs: vec![ ("key 1!".to_owned(), "val 1".to_owned()), ("key 2!".to_owned(), "val 2".to_owned()), ] .into_iter() .collect(), }; let s = qs::to_string(&data).unwrap(); assert!( s == "attrs[key+1%21]=val+1&attrs[key+2%21]=val+2" || s == "attrs[key+2%21]=val+2&attrs[key+1%21]=val+1" ); } #[test] fn test_serializer() { use serde::Serialize; #[derive(Serialize, Debug, Clone)] struct Query { a: Vec, b: &'static str, } let mut writer = Vec::new(); { let serializer = &mut qs::Serializer::new(&mut writer); let q = Query { a: vec![0, 1], b: "b", }; q.serialize(serializer).unwrap(); } assert_eq!(writer, b"a[0]=0&a[1]=1&b=b"); writer.clear(); { let serializer = &mut qs::Serializer::new(&mut writer); let q = Query { a: vec![3, 2], b: "a", }; q.serialize(serializer).unwrap(); } assert_eq!(writer, b"a[0]=3&a[1]=2&b=a"); } #[test] fn test_serializer_unit() { use serde::Serialize; #[derive(Serialize)] struct A; #[derive(Serialize)] struct B { t: (), } let mut writer = Vec::new(); { let serializer = &mut qs::Serializer::new(&mut writer); // allow this clippy lints cause I like how explicit the test is #[allow(clippy::let_unit_value)] let q = (); q.serialize(serializer).unwrap(); } assert_eq!(writer, b"", "we are testing ()"); writer.clear(); { let serializer = &mut qs::Serializer::new(&mut writer); let q = A; q.serialize(serializer).unwrap(); } assert_eq!(writer, b"", "we are testing A"); writer.clear(); { let serializer = &mut qs::Serializer::new(&mut writer); let q = B { t: () }; q.serialize(serializer).unwrap(); } assert_eq!(writer, b"t=", "we are testing B{{t: ()}}"); }