@@ -216,3 +216,106 @@ impl fmt::Debug for Contract {
216216 write ! ( f, "Contract({:?})" , Content :: from_bytes( self . as_bytes( ) ) . expect( "invariant" ) )
217217 }
218218}
219+
220+ #[ cfg( test) ]
221+ mod test {
222+ use super :: * ;
223+ use bitcoin:: hashes:: hex:: FromHex ;
224+ use std:: str:: FromStr ;
225+
226+ #[ test]
227+ fn test_json ( ) {
228+ let correct = r#"{"entity":{"domain":"tether.to"},"issuer_pubkey":"0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904","name":"Tether USD","precision":8,"ticker":"USDt","version":0}"# ;
229+ assert ! ( Contract :: from_bytes( correct. as_bytes( ) ) . is_ok( ) ) ;
230+
231+ let invalid = [
232+ // missing precision
233+ r#"{"entity":{"domain":"tether.to"},"issuer_pubkey":"0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904","name":"Tether USD","ticker":"USDt","version":0}"# ,
234+ // precision is string
235+ r#"{"entity":{"domain":"tether.to"},"issuer_pubkey":"0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904","name":"Tether USD","precision":"no","ticker":"USDt","version":0}"# ,
236+ // negative precision
237+ r#"{"entity":{"domain":"tether.to"},"issuer_pubkey":"0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904","name":"Tether USD","precision":-2,"ticker":"USDt","version":0}"# ,
238+ // too high precision
239+ r#"{"entity":{"domain":"tether.to"},"issuer_pubkey":"0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904","name":"Tether USD","precision":9,"ticker":"USDt","version":0}"# ,
240+ // missing ticker
241+ r#"{"entity":{"domain":"tether.to"},"issuer_pubkey":"0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904","name":"Tether USD","precision":8,"version":0}"# ,
242+ // ticker is int
243+ r#"{"entity":{"domain":"tether.to"},"issuer_pubkey":"0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904","name":"Tether USD","precision":8,"ticker":8,"version":0}"# ,
244+ // ticker too long
245+ r#"{"entity":{"domain":"tether.to"},"issuer_pubkey":"0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904","name":"Tether USD","precision":8,"ticker":"USDtether","version":0}"# ,
246+ ] ;
247+ for json in & invalid {
248+ assert ! ( Contract :: from_bytes( json. as_bytes( ) ) . is_err( ) , "invalid JSON was accepted: {}" , json) ;
249+ }
250+ }
251+
252+ #[ test]
253+ fn test_tether ( ) {
254+ let json = r#"{"entity":{"domain":"tether.to"},"issuer_pubkey":"0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904","name":"Tether USD","precision":8,"ticker":"USDt","version":0}"# ;
255+ let tether_id = AssetId :: from_str ( "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2" ) . unwrap ( ) ;
256+ let tether_prevout = OutPoint :: from_str ( "9596d259270ef5bac0020435e6d859aea633409483ba64e232b8ba04ce288668:0" ) . unwrap ( ) ;
257+ let tether_contract_hash = ContractHash :: from_hex ( "3c7f0a53c2ff5b99590620d7f6604a7a3a7bfbaaa6aa61f7bfc7833ca03cde82" ) . unwrap ( ) ;
258+
259+ let contract = Contract :: from_bytes ( json. as_bytes ( ) ) . unwrap ( ) ;
260+ assert_eq ! ( contract. contract_hash( ) , tether_contract_hash) ;
261+ assert_eq ! ( contract. asset_id( tether_prevout) , tether_id) ;
262+
263+ assert_eq ! ( contract. precision( ) , 8 ) ;
264+ assert_eq ! ( contract. ticker( ) , "USDt" . to_owned( ) ) ;
265+
266+ assert_eq ! ( contract. property( "name" ) . unwrap( ) , Some ( "Tether USD" . to_owned( ) ) ) ;
267+ assert_eq ! ( contract. property( "issuer_pubkey" ) . unwrap( ) ,
268+ Some ( bitcoin:: PublicKey :: from_str( "0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904" ) . unwrap( ) ) ,
269+ ) ;
270+
271+ #[ derive( Debug , PartialEq , Eq , Deserialize ) ]
272+ struct Entity {
273+ pub domain : String ,
274+ }
275+ assert_eq ! ( contract. property( "entity" ) . unwrap( ) ,
276+ Some ( Entity { domain: "tether.to" . into( ) } ) ,
277+ ) ;
278+ }
279+
280+ #[ test]
281+ fn test_cbor_wip ( ) {
282+ #[ derive( Debug , PartialEq , Eq , Deserialize , Serialize ) ]
283+ struct Entity {
284+ pub domain : String ,
285+ }
286+ #[ derive( Debug , Serialize ) ]
287+ struct ContractExtraContent {
288+ pub entity : Entity ,
289+ pub name : String ,
290+ pub issuer_pubkey : bitcoin:: PublicKey ,
291+ }
292+
293+ let extra = ContractExtraContent {
294+ entity : Entity {
295+ domain : "tether.to" . into ( ) ,
296+ } ,
297+ name : "Tether USD" . into ( ) ,
298+ issuer_pubkey : "0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904" . parse ( ) . unwrap ( ) ,
299+ } ;
300+ let cbor_content: Vec < serde_cbor:: Value > = vec ! [
301+ 8 . into( ) ,
302+ "USDt" . to_owned( ) . into( ) ,
303+ //TODO(stevenroose) optimize this as serde_cbor gets to_value
304+ serde_cbor:: from_slice:: <serde_cbor:: Value >( & serde_cbor:: to_vec( & extra) . unwrap( ) ) . unwrap( ) ,
305+ ] ;
306+
307+ // version byte
308+ let mut buffer = vec ! [ 1u8 ] ;
309+ serde_cbor:: to_writer ( & mut buffer, & cbor_content) . unwrap ( ) ;
310+ let contract = Contract :: from_bytes ( & buffer) . unwrap ( ) ;
311+
312+ assert_eq ! ( contract. contract_hash( ) , ContractHash :: hash( & buffer) ) ;
313+
314+ assert_eq ! ( contract. precision( ) , 8 ) ;
315+ assert_eq ! ( contract. ticker( ) , "USDt" . to_owned( ) ) ;
316+
317+ assert_eq ! ( contract. property( "name" ) . unwrap( ) , Some ( extra. name) ) ;
318+ assert_eq ! ( contract. property( "issuer_pubkey" ) . unwrap( ) , Some ( extra. issuer_pubkey) ) ;
319+ assert_eq ! ( contract. property( "entity" ) . unwrap( ) , Some ( extra. entity) ) ;
320+ }
321+ }
0 commit comments