diff --git a/rpc/src/v1/types/action.rs b/rpc/src/v1/types/action.rs index e42b1fc042..90a86f2e5e 100644 --- a/rpc/src/v1/types/action.rs +++ b/rpc/src/v1/types/action.rs @@ -26,7 +26,7 @@ use rustc_serialize::hex::FromHexError; use super::super::errors::ConversionError; use super::{AssetMintOutput, AssetTransferInput, AssetTransferOutput, OrderOnTransfer}; -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, PartialEq)] #[serde(rename_all = "camelCase", tag = "type")] pub enum Action { #[serde(rename_all = "camelCase")] @@ -650,3 +650,107 @@ impl From for Result { }) } } + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::{from_str, to_string}; + + #[test] + fn serialize_metadata_with_single_quotations() { + let mint = ActionWithId::MintAsset { + network_id: "ab".into(), + shard_id: 0, + metadata: "string with 'a single quotation'".to_string(), + approver: None, + administrator: None, + allowed_script_hashes: vec![], + + output: AssetMintOutput { + lock_script_hash: Default::default(), + parameters: vec![], + supply: Some(1.into()), + } + .into(), + + approvals: vec![], + id: Default::default(), + }; + let s = to_string(&mint).unwrap(); + let expected = r#"{"type":"mintAsset","networkId":"ab","shardId":0,"metadata":"string with 'a single quotation'","approver":null,"administrator":null,"allowedScriptHashes":[],"output":{"lockScriptHash":"0x0000000000000000000000000000000000000000","parameters":[],"supply":"0x1"},"approvals":[],"id":"0x0000000000000000000000000000000000000000000000000000000000000000"}"#; + assert_eq!(&s, expected); + } + + #[test] + fn parse_metadata_with_single_quotations() { + let input = r#"{"type":"mintAsset","networkId":"ab","shardId":0,"metadata":"string with 'a single quotation'","approver":null,"administrator":null,"allowedScriptHashes":[],"output":{"lockScriptHash":"0x0000000000000000000000000000000000000000","parameters":[],"supply":"0x1"},"approvals":[]}"#; + let mint = from_str(input).unwrap(); + let expected = Action::MintAsset { + network_id: "ab".into(), + shard_id: 0, + metadata: "string with 'a single quotation'".to_string(), + approver: None, + administrator: None, + allowed_script_hashes: vec![], + + output: AssetMintOutput { + lock_script_hash: Default::default(), + parameters: vec![], + supply: Some(1.into()), + } + .into(), + + approvals: vec![], + }; + assert_eq!(expected, mint); + } + + #[test] + fn parse_metadata_with_apostrophe() { + let input = r#"{"type":"mintAsset","networkId":"ab","shardId":0,"metadata":"string with 'an apostrophe’","approver":null,"administrator":null,"allowedScriptHashes":[],"output":{"lockScriptHash":"0x0000000000000000000000000000000000000000","parameters":[],"supply":"0x1"},"approvals":[]}"#; + let mint = from_str(input).unwrap(); + let expected = Action::MintAsset { + network_id: "ab".into(), + shard_id: 0, + metadata: "string with 'an apostrophe’".to_string(), + approver: None, + administrator: None, + allowed_script_hashes: vec![], + + output: AssetMintOutput { + lock_script_hash: Default::default(), + parameters: vec![], + supply: Some(1.into()), + } + .into(), + + approvals: vec![], + }; + assert_eq!(expected, mint); + } + + #[test] + fn serialize_metadata_with_apostrophe() { + let mint = ActionWithId::MintAsset { + network_id: "ab".into(), + shard_id: 0, + metadata: "string with 'an apostrophe’".to_string(), + approver: None, + administrator: None, + allowed_script_hashes: vec![], + + output: AssetMintOutput { + lock_script_hash: Default::default(), + parameters: vec![], + supply: Some(1.into()), + } + .into(), + + approvals: vec![], + id: Default::default(), + }; + let s = to_string(&mint).unwrap(); + let expected = r#"{"type":"mintAsset","networkId":"ab","shardId":0,"metadata":"string with 'an apostrophe’","approver":null,"administrator":null,"allowedScriptHashes":[],"output":{"lockScriptHash":"0x0000000000000000000000000000000000000000","parameters":[],"supply":"0x1"},"approvals":[],"id":"0x0000000000000000000000000000000000000000000000000000000000000000"}"#; + assert_eq!(&s, expected); + } +} diff --git a/rpc/src/v1/types/asset_input.rs b/rpc/src/v1/types/asset_input.rs index 00dec383b8..d3029ab319 100644 --- a/rpc/src/v1/types/asset_input.rs +++ b/rpc/src/v1/types/asset_input.rs @@ -18,7 +18,7 @@ use cjson::uint::Uint; use ctypes::transaction::{AssetOutPoint as AssetOutPointType, AssetTransferInput as AssetTransferInputType, Timelock}; use primitives::{Bytes, H256}; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct AssetOutPoint { pub tracker: H256, @@ -49,7 +49,7 @@ impl From for AssetOutPointType { } } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct AssetTransferInput { pub prev_out: AssetOutPoint, diff --git a/rpc/src/v1/types/asset_output.rs b/rpc/src/v1/types/asset_output.rs index fddae37281..061a8a13cd 100644 --- a/rpc/src/v1/types/asset_output.rs +++ b/rpc/src/v1/types/asset_output.rs @@ -22,7 +22,7 @@ use ctypes::transaction::{AssetMintOutput as AssetMintOutputType, AssetTransferO use primitives::{H160, H256}; use rustc_serialize::hex::{FromHex, FromHexError, ToHex}; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct AssetTransferOutput { pub lock_script_hash: H160, @@ -53,7 +53,7 @@ impl From for Result } } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct AssetMintOutput { pub lock_script_hash: H160, diff --git a/rpc/src/v1/types/order.rs b/rpc/src/v1/types/order.rs index 6934577872..3bba491b3c 100644 --- a/rpc/src/v1/types/order.rs +++ b/rpc/src/v1/types/order.rs @@ -20,7 +20,7 @@ use primitives::{Bytes, H160, H256}; use super::AssetOutPoint; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct Order { pub asset_type_from: H256, @@ -75,7 +75,7 @@ impl From for OrderType { } } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct OrderOnTransfer { pub order: Order, diff --git a/types/src/transaction/action.rs b/types/src/transaction/action.rs index c38952c49f..7586e9febe 100644 --- a/types/src/transaction/action.rs +++ b/types/src/transaction/action.rs @@ -1007,6 +1007,41 @@ mod tests { }); } + #[test] + fn encode_and_decode_mint_with_single_quotation() { + rlp_encode_and_decode_test!(Action::MintAsset { + network_id: "tc".into(), + shard_id: 3, + metadata: "metadata has a single quotation(')".to_string(), + output: Box::new(AssetMintOutput { + lock_script_hash: H160::random(), + parameters: vec![vec![1, 2, 3], vec![4, 5, 6], vec![0, 7]], + supply: Some(10000), + }), + approver: None, + administrator: None, + allowed_script_hashes: vec![], + approvals: vec![Signature::random()], + }); + } + + #[test] + fn encode_and_decode_mint_with_apostrophe() { + rlp_encode_and_decode_test!(Action::MintAsset { + network_id: "tc".into(), + shard_id: 3, + metadata: "metadata has an apostrophe(’)".to_string(), + output: Box::new(AssetMintOutput { + lock_script_hash: H160::random(), + parameters: vec![vec![1, 2, 3], vec![4, 5, 6], vec![0, 7]], + supply: Some(10000), + }), + approver: None, + administrator: None, + allowed_script_hashes: vec![], + approvals: vec![Signature::random()], + }); + } #[test] fn encode_and_decode_transfer_asset() {